OpenSSLSocketImpl.java revision 8c4a407e34de1b348316a9175bd1c0577c887181
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;
45615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport static libcore.io.OsConstants.*;
46615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.ErrnoException;
47615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.Libcore;
48638000042da777f6d628d88dadde957c52597710Brian Carlstromimport libcore.io.Streams;
49615225a35dbd838210270b282d1196deff643b51Brian Carlstromimport libcore.io.StructTimeval;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport org.apache.harmony.security.provider.cert.X509CertImpl;
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/**
534559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
544559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <p>
554559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * Extensions to SSLSocket include:
564559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <ul>
574559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>handshake timeout
584559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>session tickets
594559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * <li>Server Name Indication
604559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom * </ul>
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
62ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrompublic class OpenSSLSocketImpl
63ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        extends javax.net.ssl.SSLSocket
646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
65df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom
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;
7325977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    private byte[] npnProtocols;
74bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledProtocols;
75bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private String[] enabledCipherSuites;
764559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private boolean useSessionTickets;
774559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    private String hostname;
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     */
100615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    private int readTimeoutMilliseconds = 0;
101615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    private int writeTimeoutMilliseconds = 0;
102a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
103a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
104a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private String wrappedHost;
105a653cca054f36de92bbef8498be3f0f01d9d6119Brian Carlstrom    private int wrappedPort;
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1076812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
108df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
109ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        init(sslParameters);
110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1126812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
113bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                                String[] enabledProtocols,
1147695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom                                String[] enabledCipherSuites) throws IOException {
115df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom        this.socket = this;
1167695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites);
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,
1733d74b4bec8543e6e3f89eafe3afe0925f3a69f01Brian Carlstrom             NativeCrypto.getDefaultProtocols(),
1747695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom             NativeCrypto.getDefaultCipherSuites());
175ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
176ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
177ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    /**
178bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
179bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     * future handshaking.
180ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom     */
1816812a2e8bb43d9a875633a9ba255d9882c63e327Brian Carlstrom    private void init(SSLParametersImpl sslParameters,
182bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                      String[] enabledProtocols,
1837695a9b3261bfee3a810e0829bd8082fe1fcb6a4Brian Carlstrom                      String[] enabledCipherSuites) throws IOException {
184bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.sslParameters = sslParameters;
185bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledProtocols = enabledProtocols;
186bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * Gets the suitable session reference from the session cache container.
191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
192bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
19327c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        String hostName = getPeerHostName();
19427c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        int port = getPeerPort();
19527c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        if (hostName == null) {
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return null;
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
19827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
1999acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (session == null) {
2009acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2019acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2029acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2039acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String protocol = session.getProtocol();
2049acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean protocolFound = false;
2059acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
2069acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
2079acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                protocolFound = true;
2089acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2099acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2109acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2119acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!protocolFound) {
2129acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2139acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2149acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom
2159acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        String cipherSuite = session.getCipherSuite();
2169acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        boolean cipherSuiteFound = false;
2179acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
2189acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
2199acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                cipherSuiteFound = true;
2209acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom                break;
2219acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            }
2229acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2239acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        if (!cipherSuiteFound) {
2249acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom            return null;
2259acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        }
2266df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2279acacc36bafda869c6e9cc63786cdddd995ca96aBrian Carlstrom        return session;
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2305f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    private void checkOpen() throws SocketException {
2315f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        if (isClosed()) {
2325f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom            throw new SocketException("Socket is closed");
2335f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        }
2345f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    }
2355f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom
2365f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom    /**
237679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
238679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
239679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
240679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * verified if the correspondent property in java.Security is set. All
241679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
242bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom     */
243679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson    @Override public synchronized void startHandshake() throws IOException {
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
24512e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom            checkOpen();
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
247adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
248adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            } else {
249adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
252adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2536df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
2546df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
2556df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
2566df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (secureRandom == null) {
2576df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
2586df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        } else {
2596df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
2606df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
2616df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2626df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
2636df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
2646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        final int sslCtxNativePointer = (client) ?
2656df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
2666df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
2676df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
268f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        this.sslNativePointer = 0;
269f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        boolean exception = true;
270f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        try {
271f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
272f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            guard.open("close");
2736df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
27425977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson            if (npnProtocols != null) {
27525977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
27625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson            }
27725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
278f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup server certificates and private keys.
279f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // clients will receive a call back to request certificates.
280f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!client) {
2816c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
2826c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
283ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
284ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                        continue;
285ffeba5dd766602f6e2be9caa9081744348a53c04Brian Carlstrom                    }
2864ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
2876c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    if (keyType != null) {
2886c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                        keyTypes.add(keyType);
2896c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                    }
2906c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                }
2916c78b7b94c232063ec559436b48b33751373ecf1Brian Carlstrom                for (String keyType : keyTypes) {
292f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    try {
293f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
294f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       null,
295f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                                                       this));
296f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    } catch (CertificateEncodingException e) {
297f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        throw new IOException(e);
298f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    }
299ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
3006df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            }
3016df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
302f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
303f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
304f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (useSessionTickets) {
305f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
306f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
307f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (hostname != null) {
308f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
309f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
310bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
311f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
312f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (!enableSessionCreation) {
313f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
314f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                              enableSessionCreation);
315bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
316bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
317f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            AbstractSessionContext sessionContext;
318f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
319f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // look for client session to reuse
320f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
321f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = clientSessionContext;
3220c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                OpenSSLSessionImpl session = getCachedClientSession(clientSessionContext);
323f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (session != null) {
324f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
325f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                 session.sslSessionNativePointer);
326f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
327ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            } else {
328f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
329ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
330059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
331f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // setup peer certificate verification
332f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (client) {
333f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // TODO support for anonymous cipher would require us to
334f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
335f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
336f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // needing client auth takes priority...
3370c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                boolean certRequested;
338f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
339f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
340f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
341f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
342f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
343f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... over just wanting it...
344f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
345f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
346f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
347f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = true;
348f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
349f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                } else {
350f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    certRequested = false;
351f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
352f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
353f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (certRequested) {
354f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
355f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
356f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
357f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        byte[][] issuersBytes;
358f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        try {
359f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
360f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        } catch (CertificateEncodingException e) {
361f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
362f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        }
363f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
364ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                    }
365ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom                }
366ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            }
367ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
368f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Temporarily use a different timeout for the handshake process
369615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            int savedReadTimeoutMilliseconds = getSoTimeout();
370615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            int savedWriteTimeoutMilliseconds = getSoWriteTimeout();
371f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
372f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
373615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoWriteTimeout(handshakeTimeoutMilliseconds);
374f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
375bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
376f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            int sslSessionNativePointer;
377f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            try {
3785d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
37925977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols);
380f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } catch (CertificateException e) {
38154c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
38254c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                wrapper.initCause(e);
38354c8a07db3c2d1670c2867ba864d351cb30fecfaBrian Carlstrom                throw wrapper;
384bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
385f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
386f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
387f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (sslSession != null) {
388f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
389f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
390f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            } else {
391f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (!enableSessionCreation) {
392f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
393f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
394f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
395f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] localCertificates
396f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
397f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                X509Certificate[] peerCertificates
398f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
39927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
40027c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
401f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
402f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                if (handshakeCompleted) {
403f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                    sessionContext.putSession(sslSession);
404f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                }
405ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            }
406f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom
407f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // Restore the original timeout now that the handshake is complete
408f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
409615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoTimeout(savedReadTimeoutMilliseconds);
410615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                setSoWriteTimeout(savedWriteTimeoutMilliseconds);
4119d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor            }
412adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
413f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
414f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (handshakeCompleted) {
415f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom                notifyHandshakeCompletedListeners();
416f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
417ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
418f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            exception = false;
419aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        } catch (SSLProtocolException e) {
420aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            throw new SSLHandshakeException(e);
421f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        } finally {
4228a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom            // on exceptional exit, treat the socket as closed
423f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            if (exception) {
4248a720cceee7ce319d647738dfeda3f302879f370Brian Carlstrom                close();
425f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom            }
426adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
427df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    }
428adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
4296d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra    String getPeerHostName() {
430f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (wrappedHost != null) {
431f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return wrappedHost;
432f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
433f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        InetAddress inetAddress = super.getInetAddress();
434f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        if (inetAddress != null) {
435f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom            return inetAddress.getHostName();
436f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        }
437f52b35a5bc22f53b663ea22954135b69f8636bf4Brian Carlstrom        return null;
43827c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
43927c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
4406d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra    int getPeerPort() {
44127c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
44227c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson    }
44327c744cc67c7b155bd2d47551205fb1720e7e196Jesse Wilson
444df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom    /**
445df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * Return a possibly null array of X509Certificates given the
446df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     * possibly null array of DER encoded bytes.
447df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom     */
448df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
449df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (certificatesBytes == null) {
450df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            return null;
451df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
452df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
453df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
454df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            try {
455df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                certificates[i] = new X509CertImpl(certificatesBytes[i]);
456df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            } catch (IOException e) {
457df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                return null;
458df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            }
459df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        }
460df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        return certificates;
461bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
462adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
463ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
4646df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        if (alias == null) {
4656df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            return;
4666df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        }
4676df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
468aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (privateKey == null) {
469aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
470aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
4716df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
472aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        if (certificates == null) {
473aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom            return;
474aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom        }
475aba5e8c281fb9c6be23229246473fa0b433dd997Brian Carlstrom
47641e34229c07e8d05090560ff80558fa222623769Kenny Root        if (privateKey instanceof OpenSSLRSAPrivateKey) {
47741e34229c07e8d05090560ff80558fa222623769Kenny Root            OpenSSLRSAPrivateKey rsaKey = (OpenSSLRSAPrivateKey) privateKey;
47841e34229c07e8d05090560ff80558fa222623769Kenny Root            OpenSSLKey key = rsaKey.getOpenSSLKey();
47941e34229c07e8d05090560ff80558fa222623769Kenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
48041e34229c07e8d05090560ff80558fa222623769Kenny Root        } else if (privateKey instanceof OpenSSLDSAPrivateKey) {
48141e34229c07e8d05090560ff80558fa222623769Kenny Root            OpenSSLDSAPrivateKey dsaKey = (OpenSSLDSAPrivateKey) privateKey;
48241e34229c07e8d05090560ff80558fa222623769Kenny Root            OpenSSLKey key = dsaKey.getOpenSSLKey();
48341e34229c07e8d05090560ff80558fa222623769Kenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
48441e34229c07e8d05090560ff80558fa222623769Kenny Root        } else if ("PKCS#8".equals(privateKey.getFormat())) {
48541e34229c07e8d05090560ff80558fa222623769Kenny Root            byte[] privateKeyBytes = privateKey.getEncoded();
48641e34229c07e8d05090560ff80558fa222623769Kenny Root            NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
48741e34229c07e8d05090560ff80558fa222623769Kenny Root        } else {
48841e34229c07e8d05090560ff80558fa222623769Kenny Root            throw new SSLException("Unsupported PrivateKey format: " + privateKey.getFormat());
48941e34229c07e8d05090560ff80558fa222623769Kenny Root        }
49041e34229c07e8d05090560ff80558fa222623769Kenny Root
491ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
4926df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
4936df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
4946df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // checks the last installed private key and certificate,
4956df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        // so need to do this once per loop iteration
4966df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
4976df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
4986df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
4990c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
500059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
501ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            throws CertificateEncodingException, SSLException {
502059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
503059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
504059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
5054ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
506059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
507059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
508059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        X500Principal[] issuers;
509059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        if (asn1DerEncodedPrincipals == null) {
510059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = null;
511059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        } else {
512059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
513059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
514059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
515059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom            }
516059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        }
517059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
5186df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom    }
5196df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom
5200c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
521bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    public void handshakeCompleted() {
522bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        handshakeCompleted = true;
523adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
524bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // If sslSession is null, the handshake was completed during
525bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5260c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // later read operation. That means we do not need to fix up
527bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // the SSLSession and session cache or notify
528bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
529bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // startHandshake.
530bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (sslSession == null) {
531bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            return;
532bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
533adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
534bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // reset session id from the native pointer and update the
535bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // appropriate cache.
536bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        sslSession.resetId();
537bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        AbstractSessionContext sessionContext =
538bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            (sslParameters.getUseClientMode())
539bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            ? sslParameters.getClientSessionContext()
540bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                : sslParameters.getServerSessionContext();
541adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sessionContext.putSession(sslSession);
542bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
543bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        // let listeners know we are finally done
544bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        notifyHandshakeCompletedListeners();
545bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    }
546bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
547bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
548bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
549bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            // notify the listeners
550bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            HandshakeCompletedEvent event =
551bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
552bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
553bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                try {
554bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                    listener.handshakeCompleted(event);
555bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                } catch (RuntimeException e) {
556e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // The RI runs the handlers in a separate thread,
557e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // which we do not. But we try to preserve their
558e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // behavior of logging a problem and not killing
559e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // the handshaking thread just because a listener
560e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    // has a problem.
561e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    Thread thread = Thread.currentThread();
562e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
563bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom                }
564bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            }
565bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        }
566adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
567adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
5680c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5690c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
5706df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom            throws CertificateException {
571adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
572e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            if (bytes == null || bytes.length == 0) {
573e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom                throw new SSLException("Peer sent no certificate");
574e688a4123f165ed2905878e312b074b8c825d119Brian Carlstrom            }
575bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
576bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
577a5c608e59f9d574ea4bc65e9dff44aae2f34fd26Brian Carlstrom                peerCertificateChain[i] = new X509CertImpl(bytes[i]);
578adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
579bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
580bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            if (client) {
5816d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                X509TrustManager x509tm = sslParameters.getTrustManager();
5826d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                if (x509tm instanceof TrustManagerImpl) {
5836d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    TrustManagerImpl tm = (TrustManagerImpl) x509tm;
5846d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    tm.checkServerTrusted(peerCertificateChain, authMethod, wrappedHost);
5856d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                } else {
5866d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                    x509tm.checkServerTrusted(peerCertificateChain, authMethod);
5876d2a17ab04ab0967e3bff7fe6280066ef66d1d76Geremy Condra                }
588bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            } else {
5894ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
5906df6339ecd4662d351c622a59533cbbe9f275ffdBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
5914ae3fd787741bfe1b808f447dcb0785250024119Brian Carlstrom                                                                   authType);
592adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
593bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom
594bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (CertificateException e) {
595bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom            throw e;
596bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        } catch (Exception e) {
5978c4a407e34de1b348316a9175bd1c0577c887181Brian Carlstrom            throw new CertificateException(e);
598adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
599adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
600adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6010c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public InputStream getInputStream() throws IOException {
6025f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
603ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (is == null) {
605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                is = new SSLInputStream();
606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
607adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return is;
609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6120c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
6135f2e6872311240319509aed64d9f58cd5b64719bBrian Carlstrom        checkOpen();
614ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom        synchronized (this) {
615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (os == null) {
616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                os = new SSLOutputStream();
617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return os;
620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
623bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom    /**
624adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides input data stream functionality
625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * read data received via SSL protocol.
627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLInputStream extends InputStream {
629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLInputStream() throws IOException {
630679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            /*
631679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson             * Note: When startHandshake() throws an exception, no
632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             * SSLInputStream object will be created.
633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
634679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * this operation can block until the data will be
640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * available.
641adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @return read value.
642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @throws <code>IOException</code>
643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6444559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int read() throws IOException {
646638000042da777f6d628d88dadde957c52597710Brian Carlstrom            return Streams.readSingleByte(this);
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
648adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6534559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
654a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
6555900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
656ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (readLock) {
65712e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
658a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
659a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
66012e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return 0;
66112e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
6625d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
6635d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
667adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
669adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * This inner class provides output data stream functionality
670adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * for the OpenSSL native implementation. It is used to
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     * write data according to the encryption parameters given in SSL context.
672adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project     */
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private class SSLOutputStream extends OutputStream {
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        SSLOutputStream() throws IOException {
675679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            /*
676679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson             * Note: When startHandshake() throws an exception, no
677ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom             * SSLOutputStream object will be created.
678adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project             */
679679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
680adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
683adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(int)
685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6864559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
687638000042da777f6d628d88dadde957c52597710Brian Carlstrom        public void write(int oneByte) throws IOException {
688638000042da777f6d628d88dadde957c52597710Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
690adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        /**
692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * Method acts as described in spec for superclass.
693adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
694adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project         */
6954559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        @Override
696a1603838fe9e865575c87982e32c6343740e464cElliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
6975900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
698ef628d1464e57552403ad43366e153c1ef50b926Brian Carlstrom            synchronized (writeLock) {
69912e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                checkOpen();
700a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
701a1603838fe9e865575c87982e32c6343740e464cElliott Hughes                if (byteCount == 0) {
70212e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                    return;
70312e7cb011c48b228cdeb2b799fff54d7fbfc6d85Brian Carlstrom                }
7045d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
705615225a35dbd838210270b282d1196deff643b51Brian Carlstrom                        OpenSSLSocketImpl.this, buf, offset, byteCount, writeTimeoutMilliseconds);
706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
707adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
710adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7110c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public SSLSession getSession() {
712df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom        if (sslSession == null) {
713df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            try {
714679ac55c3c037887edfc6ce6f42a23cd7c11cd12Jesse Wilson                startHandshake();
715df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            } catch (IOException e) {
716df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // return an invalid session with
717df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
718df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
719df349b3eaf4d1fa0643ab722173bc3bf20a266f5Brian Carlstrom            }
720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslSession;
722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7240c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void addHandshakeCompletedListener(
725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
7300c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        listeners.add(listener);
733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7350c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void removeHandshakeCompletedListener(
736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            HandshakeCompletedListener listener) {
737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listener == null) {
738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
739adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (listeners == null) {
741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!listeners.remove(listener)) {
745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    "Provided listener is not registered");
747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
748adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7500c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getEnableSessionCreation() {
751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getEnableSessionCreation();
752adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7540c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7580c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedCipherSuites() {
759ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
761adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7620c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledCipherSuites() {
763bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledCipherSuites.clone();
764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7660c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
767bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
768adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7700c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getSupportedProtocols() {
771ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7740c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public String[] getEnabledProtocols() {
775bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        return enabledProtocols.clone();
776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
7780c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
779bcfb325d5b1f9529b439cc0805a1c140521510f7Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    /**
7834559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables session ticket support.
7844559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
7854559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param useSessionTickets True to enable session tickets
7864559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
7874559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
7884559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.useSessionTickets = useSessionTickets;
7894559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
7904559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
7914559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    /**
7924559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * This method enables Server Name Indication
7934559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     *
7944559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
7954559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom     */
7964559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    public void setHostname(String hostname) {
7974559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom        this.hostname = hostname;
7984559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom    }
7994559b1d37edcb5d7f1da086cf2e3290388d74f46Brian Carlstrom
8000c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getUseClientMode() {
801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getUseClientMode();
802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8040c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setUseClientMode(boolean mode) {
805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (handshakeStarted) {
806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalArgumentException(
8070c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                    "Could not change the mode after the initial handshake has begun.");
808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setUseClientMode(mode);
810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8120c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getWantClientAuth() {
813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getWantClientAuth();
814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8160c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public boolean getNeedClientAuth() {
817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return sslParameters.getNeedClientAuth();
818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8200c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setNeedClientAuth(boolean need) {
821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setNeedClientAuth(need);
822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8240c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setWantClientAuth(boolean want) {
825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        sslParameters.setWantClientAuth(want);
826adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8280c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
8290c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8320c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
8330c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
836615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    @Override public void setSoTimeout(int readTimeoutMilliseconds) throws SocketException {
837615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        super.setSoTimeout(readTimeoutMilliseconds);
838615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.readTimeoutMilliseconds = readTimeoutMilliseconds;
839a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom    }
840a4a95792af235d4bf3256eab3208f74fae8ec262Brian Carlstrom
8410c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public int getSoTimeout() throws SocketException {
842615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        return readTimeoutMilliseconds;
843615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    }
844615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
845615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    /**
846615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
847615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     */
848615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public void setSoWriteTimeout(int writeTimeoutMilliseconds) throws SocketException {
849615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.writeTimeoutMilliseconds = writeTimeoutMilliseconds;
850615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
851615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        StructTimeval tv = StructTimeval.fromMillis(writeTimeoutMilliseconds);
852615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        try {
853615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            Libcore.os.setsockoptTimeval(getFileDescriptor$(), SOL_SOCKET, SO_SNDTIMEO, tv);
854615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        } catch (ErrnoException errnoException) {
855615225a35dbd838210270b282d1196deff643b51Brian Carlstrom            throw errnoException.rethrowAsSocketException();
856615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        }
857615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    }
858615225a35dbd838210270b282d1196deff643b51Brian Carlstrom
859615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    /**
860615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     * Note write timeouts are not part of the javax.net.ssl.SSLSocket API
861615225a35dbd838210270b282d1196deff643b51Brian Carlstrom     */
862615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public int getSoWriteTimeout() throws SocketException {
863615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        return writeTimeoutMilliseconds;
864adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
865adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
8669d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    /**
8679d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
8689d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     * milliseconds and will be used only during the handshake process.
8699d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor     */
870615225a35dbd838210270b282d1196deff643b51Brian Carlstrom    public void setHandshakeTimeout(int handshakeTimeoutMilliseconds) throws SocketException {
871615225a35dbd838210270b282d1196deff643b51Brian Carlstrom        this.handshakeTimeoutMilliseconds = handshakeTimeoutMilliseconds;
8729d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor    }
8739d48f97ae59510bac2b91dac2cc22d519cbf1bc7Dan Egnor
8740c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson    @Override public void close() throws IOException {
8750c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
876adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
877adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (handshakeLock) {
878adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (!handshakeStarted) {
8790c58d22d44cfb56f0c80f0fa1c69297ba45f3afcJesse Wilson                // prevent further attempts to start handshake
880adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                handshakeStarted = true;
881ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
882adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (this) {
883ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom                    free();
884adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
885df9c090e85c4d052cdd17b5f981819be86a56737Brian Carlstrom                    if (socket != this) {
886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } else {
888adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (!super.isClosed()) super.close();
889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
890adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
891ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom
892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                return;
893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
895adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
897adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
898783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            // Interrupt any outstanding reads or writes before taking the writeLock and readLock
899783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
900df9f5967a3b8dc2f61183d155791393b67980511Brian Carlstrom
901783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom            synchronized (writeLock) {
902783004cceef470884b3ee6946cbbfc4af0f28ae7Brian Carlstrom                synchronized (readLock) {
903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    // Shut down the SSL connection, per se.
904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (handshakeStarted) {
9065900e5546059f05d5e58e5732e4d08d83b8b7574Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
9075d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
9085d3f5200f3511c9a7107bcc0a996c7afa1b39aafElliott Hughes                                    this);
909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
9101c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                    } catch (IOException ignored) {
911adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        /*
9121c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * Note that although close() can throw
9131c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * IOException, the RI does not throw if there
9141c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * is problem sending a "close notify" which
9151c64b3adb85345659ac60ad82216268acba18764Brian Carlstrom                         * can happen if the underlying socket is closed.
916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                         */
917d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                    } finally {
918d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        /*
919d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * Even if the above call failed, it is still safe to free
920d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * the native structs, and we need to do so lest we leak
921d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         * memory.
922d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                         */
923d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        free();
924d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom
925d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        if (socket != this) {
926d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
927d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                socket.close();
928d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
929d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        } else {
930d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            if (!super.isClosed()) {
931d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                                super.close();
932d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                            }
933d3433cea484f380ab2c889c10e9d9d3268046a6cBrian Carlstrom                        }
934adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
935adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
936adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
937adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
938adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
939adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
940ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    private void free() {
941ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        if (sslNativePointer == 0) {
942ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom            return;
943ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        }
944ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
945ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom        sslNativePointer = 0;
946f7aab022dcbfcd8f27b409ab92b4bca4a84d0b8aBrian Carlstrom        guard.close();
947ecaf759ba374a3e53613c97b47920bf520bb93cfBrian Carlstrom    }
948adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
949e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom    @Override protected void finalize() throws Throwable {
950e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        try {
951e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            /*
952e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * Just worry about our own state. Notably we do not try and
953e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * close anything. The SocketImpl, either our own
954e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
955e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
956e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * if you want to do that, properly close the socket yourself.
957e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             *
958e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
959e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
960e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
961e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
962e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
963e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
964e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * and will write the close notify to some unsuspecting
965e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             * reader.
966e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom             */
96712f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            if (guard != null) {
96812f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom                guard.warnIfOpen();
96912f2d8e2760b78c673b7a187b9062b3938a03147Brian Carlstrom            }
970e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            free();
971e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        } finally {
972e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom            super.finalize();
973e2f58c9501eac730d048199906dc41fe8e4cd6e9Brian Carlstrom        }
974adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
9753267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey
9763267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    @Override
9773267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
9783267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        if (socket == this) {
9793267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return super.getFileDescriptor$();
9803267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        } else {
9813267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey            return socket.getFileDescriptor$();
9823267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey        }
9833267a46b52d848e1e9e20c226512688f0c50d4c3Jeff Sharkey    }
98425977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
98525977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    /**
98625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
98725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * protocol was agreed upon.
98825977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     */
98925977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    public byte[] getNpnSelectedProtocol() {
990600dc4949de6bf5608e5f5a5214cde59299b683aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
99125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    }
99225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson
99325977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    /**
99425977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * Sets the list of protocols this peer is interested in. If null no
99525977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     * protocols will be used.
99625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     *
9971982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
9981982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
9991982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
10001982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
100125977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson     */
100225977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
10031982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
10041982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
10051982194cb9067e3311ac491b4d02a6ead611fd59Jesse Wilson        }
100625977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson        this.npnProtocols = npnProtocols;
100725977e422febea04dac9fb9c35d7271d55d3b6b8Jesse Wilson    }
1008adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
1009