OpenSSLSocketImpl.java revision 5006f3bedbfd19dc905416bbf28bb0e95807f845
108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/*
208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * you may not use this file except in compliance with the License.
608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * You may obtain a copy of the License at
708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project *
1008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * See the License for the specific language governing permissions and
1408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * limitations under the License.
1508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
1608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectpackage org.apache.harmony.xnet.provider.jsse;
1808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrickimport dalvik.system.BlockGuard;
20fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport dalvik.system.CloseGuard;
2108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.IOException;
2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.InputStream;
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.OutputStream;
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.InetAddress;
2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.Socket;
2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.SocketException;
2798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.PrivateKey;
2898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.SecureRandom;
291f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstromimport java.security.cert.CertificateEncodingException;
3008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.CertificateException;
3108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.X509Certificate;
3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.ArrayList;
3397e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughesimport java.util.Arrays;
34d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstromimport java.util.HashSet;
35d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstromimport java.util.Set;
3608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException;
39edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException;
408765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstromimport javax.net.ssl.SSLProtocolException;
4108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
42fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager;
4398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal;
4408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport org.apache.harmony.security.provider.cert.X509CertImpl;
4508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
470b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
480b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
4908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
50f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom * later, for example in the package.html or a separate reference document.
510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include:
530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul>
540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout
550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>compression methods
560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets
570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication
580b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul>
5908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
60f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl
61f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        extends javax.net.ssl.SSLSocket
6298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
6390ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom
64f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private int sslNativePointer;
6508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private InputStream is;
6608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OutputStream os;
6708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private final Object handshakeLock = new Object();
68f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object readLock = new Object();
69f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object writeLock = new Object();
70cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private SSLParametersImpl sslParameters;
712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private String[] enabledProtocols;
722828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private String[] enabledCipherSuites;
730b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private String[] enabledCompressionMethods;
740b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private boolean useSessionTickets;
750b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private String hostname;
7608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OpenSSLSessionImpl sslSession;
7790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private final Socket socket;
7808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private boolean autoClose;
7908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private boolean handshakeStarted = false;
80f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom    private final CloseGuard guard = CloseGuard.get();
812828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
822828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Not set to true until the update from native that tells us the
842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * full handshake is complete, since SSL_do_handshake can return
852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * before the handshake is completely done due to
862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * handshake_cutthrough support.
872828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private boolean handshakeCompleted = false;
892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
9008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private ArrayList<HandshakeCompletedListener> listeners;
9172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
9272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    /**
9372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
9472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * write for non-wrapped sockets. Note that
9572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
9672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
9772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     */
9872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int timeoutMilliseconds = 0;
9972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
10072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
1016e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom    private String wrappedHost;
1026e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom    private int wrappedPort;
10308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
104cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
10590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
106f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
10708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
10808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
109cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
1102828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                                String[] enabledProtocols,
1110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                                String[] enabledCipherSuites,
1120b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                                String[] enabledCompressionMethods) throws IOException {
11390ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
1140b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites, enabledCompressionMethods);
1152828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
1162828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
117cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
11890ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
11908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port);
12090ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
121f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
12208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
12308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
124cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
12590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
12608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port);
12790ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
128f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
12908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
13008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
13108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
132c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
133c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
1345006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
13508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port, clientAddress, clientPort);
13690ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
137f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
13808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
13908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
14008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
141c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
1425006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                                SSLParametersImpl sslParameters) throws IOException {
14308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port, clientAddress, clientPort);
14490ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
145f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
14608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
14708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
14808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
1495006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Create an SSL socket that wraps another socket. Invoked by
1505006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * OpenSSLSocketImplWrapper constructor.
15108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
15208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
153cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
15408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.socket = socket;
1556e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedHost = host;
1566e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedPort = port;
15708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.autoClose = autoClose;
158f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
15972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
16072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // this.timeout is not set intentionally.
16172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
16272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // to wrapped socket
163f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
164f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
165f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
166f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * Initialize the SSL socket and set the certificates for the
167f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * future handshaking.
168f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
169cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters) throws IOException {
1702828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        init(sslParameters,
1712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom             NativeCrypto.getSupportedProtocols(),
1720b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom             NativeCrypto.getDefaultCipherSuites(),
1730b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom             NativeCrypto.getDefaultCompressionMethods());
174f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
175f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
176f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
1772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
1782828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * future handshaking.
179f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
180cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters,
1812828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                      String[] enabledProtocols,
1820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                      String[] enabledCipherSuites,
1830b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                      String[] enabledCompressionMethods) throws IOException {
1842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.sslParameters = sslParameters;
1852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledProtocols = enabledProtocols;
1862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
1870b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.enabledCompressionMethods = enabledCompressionMethods;
18808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
18908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
19108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Gets the suitable session reference from the session cache container.
19208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
1932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
19408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (super.getInetAddress() == null ||
19508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getInetAddress().getHostAddress() == null ||
19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getInetAddress().getHostName() == null) {
19708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
19808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
19961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(
20008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getInetAddress().getHostName(),
20108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getPort());
20261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (session == null) {
20361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
20461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
20561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
20661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String protocol = session.getProtocol();
20761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean protocolFound = false;
20861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
20961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
21061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                protocolFound = true;
21161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
21261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
21361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
21461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!protocolFound) {
21561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
21661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
21761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
21861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String cipherSuite = session.getCipherSuite();
21961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean cipherSuiteFound = false;
22061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
22161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
22261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                cipherSuiteFound = true;
22361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
22461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
22561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
22661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!cipherSuiteFound) {
22761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
22861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
22998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2300b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        String compressionMethod = session.getCompressionMethod();
2310b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        boolean compressionMethodFound = false;
2320b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        for (String enabledCompressionMethod : enabledCompressionMethods) {
2330b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            if (compressionMethod.equals(enabledCompressionMethod)) {
2340b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                compressionMethodFound = true;
2350b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                break;
2360b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            }
2370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        }
2380b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        if (!compressionMethodFound) {
2390b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            return null;
2400b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        }
2410b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
24261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        return session;
24308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
24408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
24508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
24608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Starts a TLS/SSL handshake on this connection using some native methods
24708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * from the OpenSSL library. It can negotiate new encryption keys, change
24808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * cipher suites, or initiate a new session. The certificate chain is
24908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * verified if the correspondent property in java.Security is set. All
250f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * listeners are notified at the end of the TLS/SSL handshake.
25108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
2520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
2532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void startHandshake() throws IOException {
2542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        startHandshake(true);
2552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
2562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
257a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
258a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
259a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
260a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
261a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
262a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
263a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
2642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Perform the handshake
2655006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     *
2662828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @param full If true, disable handshake cutthrough for a fully synchronous handshake
2672828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
2682828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public synchronized void startHandshake(boolean full) throws IOException {
26908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
2707b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom            checkOpen();
27108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
27208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
27308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
27408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
27508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
27608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
27708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
27898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
28098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
28198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
28298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
28398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
28498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
28598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
28698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
28798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
28898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
28998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int sslCtxNativePointer = (client) ?
29098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
29198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
29298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
293fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        this.sslNativePointer = 0;
294fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        boolean exception = true;
295fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
296fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
297fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
29898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
299fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup server certificates and private keys.
300fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // clients will receive a call back to request certificates.
301fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!client) {
302d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
303d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
304aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
305aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                        continue;
306aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    }
307ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
308d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    if (keyType != null) {
309d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                        keyTypes.add(keyType);
310d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    }
311d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                }
312d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String keyType : keyTypes) {
313fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    try {
314fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
315fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       null,
316fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       this));
317fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    } catch (CertificateEncodingException e) {
318fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        throw new IOException(e);
319fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    }
320f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
32198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            }
32298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
323fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
324fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
325fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (enabledCompressionMethods.length != 0) {
326fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.setEnabledCompressionMethods(sslNativePointer,
327fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                          enabledCompressionMethods);
328fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
329fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (useSessionTickets) {
330fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
331fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
332fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (hostname != null) {
333fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
334fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3352828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
336fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
337fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
338fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
339fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                              enableSessionCreation);
3402828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
3412828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
342fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            AbstractSessionContext sessionContext;
343fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
344fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // look for client session to reuse
345fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
346fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = clientSessionContext;
3475006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                OpenSSLSessionImpl session = getCachedClientSession(clientSessionContext);
348fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (session != null) {
349fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
350fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                 session.sslSessionNativePointer);
351fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
352f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            } else {
353fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
354f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
35598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
356fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup peer certificate verification
357fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
358fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // TODO support for anonymous cipher would require us to
359fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
360fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
361fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // needing client auth takes priority...
3625006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                boolean certRequested;
363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
365fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
366fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
367fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
368fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... over just wanting it...
369fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
370fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
371fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
372fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
373fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
374fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else {
375fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = false;
376fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
377fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
378fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (certRequested) {
379fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
380fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
381fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
382fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        byte[][] issuersBytes;
383fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        try {
384fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
385fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        } catch (CertificateEncodingException e) {
386fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
387fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        }
388fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
389f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                    }
390f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
391f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
392f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
393fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client && full) {
394fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // we want to do a full synchronous handshake, so turn off cutthrough
395fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_mode(sslNativePointer,
396fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                            NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
397fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
398f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
399fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
400fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int savedTimeoutMilliseconds = getSoTimeout();
401fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
402fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
403fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
4042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
405fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int sslSessionNativePointer;
406fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
407a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
408a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        socket.getFileDescriptor$(), this, getSoTimeout(), client);
409fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
410d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
411d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
412d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
4132828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
414fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
415fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
416fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (sslSession != null) {
417fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
418fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
419fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
420fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (!enableSessionCreation) {
421fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
422fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
423fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
424fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] localCertificates
425fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
426fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] peerCertificates
427fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
428fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (wrappedHost == null) {
429fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
430fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        localCertificates, peerCertificates,
431fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        super.getInetAddress().getHostName(),
432fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        super.getPort(), sessionContext);
433fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else  {
434fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
435fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        localCertificates, peerCertificates,
436fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        wrappedHost, wrappedPort,
437fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        sessionContext);
438fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
439fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
440fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (handshakeCompleted) {
441fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sessionContext.putSession(sslSession);
442fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
443f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            }
444fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
445fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
446fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
447fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(savedTimeoutMilliseconds);
448331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
44908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
450fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
451fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
452fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
453fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
454f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
455fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            exception = false;
4568765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        } catch (SSLProtocolException e) {
4578765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            throw new SSLHandshakeException(e);
458fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
459aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
460fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (exception) {
461aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom                close();
462fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
46308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
464e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
46508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
466e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    /**
467e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * Return a possibly null array of X509Certificates given the
468e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * possibly null array of DER encoded bytes.
469e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     */
47090ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
471e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (certificatesBytes == null) {
472e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            return null;
473e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
474e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
475e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
476e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
477e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                certificates[i] = new X509CertImpl(certificatesBytes[i]);
478e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
479e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return null;
480e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
481e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
482e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        return certificates;
4832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
48408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
485f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
48698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (alias == null) {
48798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            return;
48898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
48998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
4908765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (privateKey == null) {
4918765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
4928765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
49398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
4948765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (certificates == null) {
4958765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
4968765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
4978765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom
4988765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        byte[] privateKeyBytes = privateKey.getEncoded();
499f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
5008765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
50198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
50298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
50398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // checks the last installed private key and certificate,
50498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // so need to do this once per loop iteration
50598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
50698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
50798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5085006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
50998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
510f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
51198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
51298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
51398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
514ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
51598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
51698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
51798a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        X500Principal[] issuers;
51898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        if (asn1DerEncodedPrincipals == null) {
51998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = null;
52098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        } else {
52198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
52298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
52398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
52498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            }
52598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
52698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
52798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
52898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5295006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
5302828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void handshakeCompleted() {
5312828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        handshakeCompleted = true;
53208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5332828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // If sslSession is null, the handshake was completed during
5342828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5355006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // later read operation. That means we do not need to fix up
5362828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the SSLSession and session cache or notify
5372828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
5382828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // startHandshake.
5392828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (sslSession == null) {
5402828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return;
5412828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
54208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5432828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
5442828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
5452828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
5462828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
5472828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
5482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
5492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
55008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
5512828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5522828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
5532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
5542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
5552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
5572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
5582828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
5592828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
5602828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
5612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
5622828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
5632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
5642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
565371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
566371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
567371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
568371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
569371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
570371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
571371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
5722828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
5732828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
5742828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
57508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
57608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5775006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5785006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
57998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
58008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
581371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            if (bytes == null || bytes.length == 0) {
582371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
583371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
5842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
5852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
5866e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom                peerCertificateChain[i] = new X509CertImpl(bytes[i]);
58708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
5882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
5892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
59098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
59198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                                                                   authMethod);
5922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
593ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
59498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
595ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                                                                   authType);
59608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
5972828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5982828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
5992828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
6003a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom        } catch (RuntimeException e) {
6013a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom            throw e;
6022828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
6032828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw new RuntimeException(e);
60408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
60508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
60608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6075006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public InputStream getInputStream() throws IOException {
608a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
609f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
61008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
61108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
61208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
61308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
61408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return is;
61508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
61608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
61708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6185006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
619a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
620f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
62108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
62208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
62308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
62408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
62508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return os;
62608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
62708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
62808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6292828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
63008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
63108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
63208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
63308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
63408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
63508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLInputStream() throws IOException {
63608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /**
63708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /* Note: When startHandshake() throws an exception, no
63808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             * SSLInputStream object will be created.
63908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
6402828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
64108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
64208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
64308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
64408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * this operation can block until the data will be
64608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * available.
64708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @return read value.
64808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @throws <code>IOException</code>
64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
652ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
653f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6547b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
655a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read_byte(sslNativePointer, socket.getFileDescriptor$(),
656a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, getSoTimeout());
65708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
65808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
65908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
66008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
66108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
66208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
66308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6640b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
66597e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
666ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
667f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6687b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
66997e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
67097e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
6717b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return 0;
6727b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
673a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
674a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
67508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
67608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
67808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
67908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
68008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
68108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
68208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
68308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
68408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
68508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLOutputStream() throws IOException {
68608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /**
68708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /* Note: When startHandshake() throws an exception, no
688f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom             * SSLOutputStream object will be created.
68908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
6902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
69108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
69208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
69308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
69408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
69508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
69608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6970b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
69808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public void write(int b) throws IOException {
699ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
700f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7017b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
702a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write_byte(sslNativePointer, socket.getFileDescriptor$(),
703a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, b);
70408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
70508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
70608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
70708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
70808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
70908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
71008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
71297e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
713ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
714f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7157b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
71697e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
71797e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
7187b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return;
7197b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
720a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
721a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount);
72208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
72308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
72408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
72508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
72608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7275006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public SSLSession getSession() {
728e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
729e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
730e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                startHandshake(true);
731e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
732e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
733e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
734e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
735e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
73608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
73708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
73808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
73908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7405006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void addHandshakeCompletedListener(
74108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
74208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
74308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
74408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
7465006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
74708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
74808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
74908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
75008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7515006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void removeHandshakeCompletedListener(
75208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
75308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
75408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
75508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
75708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
75808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
75908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
76108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
76208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
76308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
76508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7665006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getEnableSessionCreation() {
76708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
76908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7705006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
77108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
77208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7745006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedCipherSuites() {
775f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
77608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7785006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledCipherSuites() {
7792828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledCipherSuites.clone();
78008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7825006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
7832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
78408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7865006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedProtocols() {
787f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
78808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7905006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledProtocols() {
7912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledProtocols.clone();
79208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7945006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
7952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
79608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
79808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
7990b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods that may be used on this SSL
8000b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * connection.
8010b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
8020b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8030b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getSupportedCompressionMethods() {
8040b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return NativeCrypto.getSupportedCompressionMethods();
8050b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8060b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8070b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods versions that are in use
8090b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * on this SSL connection.
8100b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
8120b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8130b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getEnabledCompressionMethods() {
8140b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return enabledCompressionMethods.clone();
8150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8170b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8185006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Enables compression methods listed by getSupportedCompressionMethods().
8190b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8200b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @throws IllegalArgumentException when one or more of the names in the
8210b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *             array are not supported, or when the array is null.
8220b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8235006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    public void setEnabledCompressionMethods(String[] methods) {
8240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods);
8250b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8260b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8270b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8280b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
8290b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8300b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8310b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8320b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8330b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8340b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8350b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8360b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
8380b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8390b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8400b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8410b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
8420b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.hostname = hostname;
8430b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8440b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8455006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getUseClientMode() {
84608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
84708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
84808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8495006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setUseClientMode(boolean mode) {
85008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (handshakeStarted) {
85108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
8525006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                    "Could not change the mode after the initial handshake has begun.");
85308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
85408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
85508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
85608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8575006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getWantClientAuth() {
85808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
85908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8615006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getNeedClientAuth() {
86208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
86308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8655006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setNeedClientAuth(boolean need) {
86608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
86708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8695006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setWantClientAuth(boolean want) {
87008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
87108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8735006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
8745006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
87508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8775006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
8785006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
87908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
88008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8815006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
88272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        super.setSoTimeout(timeoutMilliseconds);
88372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.timeoutMilliseconds = timeoutMilliseconds;
88472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
88572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
8865006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public int getSoTimeout() throws SocketException {
88772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        return timeoutMilliseconds;
88808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
88908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
890331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
891331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
892331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
893331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
89472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
89572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
896331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
897331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
8985006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void close() throws IOException {
8995006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
90008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
90108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
90208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
9035006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                // prevent further attempts to start handshake
90408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
905f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
90608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (this) {
907f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
90808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
90990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
91008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
91108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
91208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed()) super.close();
91308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
91408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
915f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
91608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
91708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
91808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
91908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
92058a44774b954fed596ee22307a231de783ea8121Brian Carlstrom        NativeCrypto.SSL_interrupt(sslNativePointer);
92108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
92208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (this) {
92308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            synchronized (writeLock) {
92408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (readLock) {
92508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
92608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    // Shut down the SSL connection, per se.
92708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    try {
92808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (handshakeStarted) {
929ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
930a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
931a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                                    this);
93208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        }
93386c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                    } catch (IOException ignored) {
93408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        /*
93586c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * Note that although close() can throw
93686c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * IOException, the RI does not throw if there
93786c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * is problem sending a "close notify" which
93886c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * can happen if the underlying socket is closed.
93908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                         */
94008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
94108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
94208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    /*
94308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     * Even if the above call failed, it is still safe to free
94408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     * the native structs, and we need to do so lest we leak
94508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     * memory.
94608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     */
947f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
94808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
94990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
95008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed())
95108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                            socket.close();
95208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
95308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed())
95408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                            super.close();
95508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
95608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
95708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
95808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
95908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
96008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
961f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private void free() {
962f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        if (sslNativePointer == 0) {
963f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            return;
964f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        }
965f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
966f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        sslNativePointer = 0;
967fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        guard.close();
968f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
96908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9701990574e420184f3ad43400171f624dad44700d8Brian Carlstrom    @Override protected void finalize() throws Throwable {
9711990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
9721990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            /*
9731990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * Just worry about our own state. Notably we do not try and
9741990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * close anything. The SocketImpl, either our own
9751990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
9761990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
9771990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * if you want to do that, properly close the socket yourself.
9781990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             *
9791990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
9801990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
9811990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
9821990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
9831990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
9841990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
9851990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * and will write the close notify to some unsuspecting
9861990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * reader.
9871990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             */
988f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            if (guard != null) {
989f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom                guard.warnIfOpen();
990f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            }
9911990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            free();
9921990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
9931990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
9941990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
99508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
99608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
997