OpenSSLSocketImpl.java revision fa6657aaf2fadbb1aeb2f869cba82042c1faedea
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;
210648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkeyimport java.io.FileDescriptor;
2208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.IOException;
2308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.InputStream;
2408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.io.OutputStream;
2508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.InetAddress;
2608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.Socket;
2708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.net.SocketException;
2898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.PrivateKey;
2998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstromimport java.security.SecureRandom;
301f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstromimport java.security.cert.CertificateEncodingException;
3108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.CertificateException;
3208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.security.cert.X509Certificate;
3308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.ArrayList;
3497e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughesimport java.util.Arrays;
35d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstromimport java.util.HashSet;
36d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstromimport java.util.Set;
3708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
3908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException;
40edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException;
418765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstromimport javax.net.ssl.SSLProtocolException;
4208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
43fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager;
4498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal;
455c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstromimport libcore.io.Streams;
4608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport org.apache.harmony.security.provider.cert.X509CertImpl;
4708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project/**
490b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Implementation of the class OpenSSLSocketImpl based on OpenSSL.
500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include:
520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul>
530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout
540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>compression methods
550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets
560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication
570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul>
5808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
59f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl
60f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        extends javax.net.ssl.SSLSocket
6198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
6290ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom
63f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private int sslNativePointer;
6408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private InputStream is;
6508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OutputStream os;
6608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private final Object handshakeLock = new Object();
67f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object readLock = new Object();
68f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object writeLock = new Object();
69cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private SSLParametersImpl sslParameters;
70721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    private byte[] npnProtocols;
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,
1717fce41e05553f8edd1468a68eafb40249a6337cbBrian Carlstrom             NativeCrypto.getDefaultProtocols(),
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) {
1943967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        String hostName = getPeerHostName();
1953967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        int port = getPeerPort();
1963967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        if (hostName == null) {
19708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
19808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
1993967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(hostName, port);
20061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (session == null) {
20161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
20261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
20361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
20461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String protocol = session.getProtocol();
20561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean protocolFound = false;
20661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
20761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
20861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                protocolFound = true;
20961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
21061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
21161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
21261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!protocolFound) {
21361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
21461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
21561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
21661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String cipherSuite = session.getCipherSuite();
21761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean cipherSuiteFound = false;
21861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
21961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
22061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                cipherSuiteFound = true;
22161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
22261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
22361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
22461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!cipherSuiteFound) {
22561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
22661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
22798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2280b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        String compressionMethod = session.getCompressionMethod();
2293967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        if (!compressionMethod.equals(NativeCrypto.SUPPORTED_COMPRESSION_METHOD_NULL)) {
2303967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson            boolean compressionMethodFound = false;
2313967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson            for (String enabledCompressionMethod : enabledCompressionMethods) {
2323967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                if (compressionMethod.equals(enabledCompressionMethod)) {
2333967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                    compressionMethodFound = true;
2343967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                    break;
2353967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                }
2363967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson            }
2373967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson            if (!compressionMethodFound) {
2383967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                return null;
2390b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            }
2400b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        }
2410b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
24261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        return session;
24308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
24408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
245a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
246a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
247a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
248a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
249a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
250a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
251a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
252d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * Starts a TLS/SSL handshake on this connection using some native methods
253d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * from the OpenSSL library. It can negotiate new encryption keys, change
254d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * cipher suites, or initiate a new session. The certificate chain is
255d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * verified if the correspondent property in java.Security is set. All
256d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson     * listeners are notified at the end of the TLS/SSL handshake.
2572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
258d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson    @Override public synchronized void startHandshake() throws IOException {
25908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
2607b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom            checkOpen();
26108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
26208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
26308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
26408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
26508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
26608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
26708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
26898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
26998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
27098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
27198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
27298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
27398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
27498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
27598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
27698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
27798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
27898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int sslCtxNativePointer = (client) ?
28098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
28198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
28298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
283fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        this.sslNativePointer = 0;
284fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        boolean exception = true;
285fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
286fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
287fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
28898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
289721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson            if (npnProtocols != null) {
290721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
291721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson            }
292721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
293fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup server certificates and private keys.
294fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // clients will receive a call back to request certificates.
295fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!client) {
296d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
297d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
298aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
299aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                        continue;
300aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    }
301ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
302d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    if (keyType != null) {
303d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                        keyTypes.add(keyType);
304d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    }
305d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                }
306d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String keyType : keyTypes) {
307fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    try {
308fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
309fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       null,
310fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       this));
311fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    } catch (CertificateEncodingException e) {
312fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        throw new IOException(e);
313fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    }
314f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
31598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            }
31698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
317fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
318fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
319fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (enabledCompressionMethods.length != 0) {
320fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.setEnabledCompressionMethods(sslNativePointer,
321fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                          enabledCompressionMethods);
322fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
323fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (useSessionTickets) {
324fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
325fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
326fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (hostname != null) {
327fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
328fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3292828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
330fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
331fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
332fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
333fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                              enableSessionCreation);
3342828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
3352828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
336fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            AbstractSessionContext sessionContext;
337fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
338fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // look for client session to reuse
339fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
340fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = clientSessionContext;
3415006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                OpenSSLSessionImpl session = getCachedClientSession(clientSessionContext);
342fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (session != null) {
343fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
344fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                 session.sslSessionNativePointer);
345fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
346f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            } else {
347fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
348f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
34998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
350fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup peer certificate verification
351fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
352fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // TODO support for anonymous cipher would require us to
353fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
354fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
355fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // needing client auth takes priority...
3565006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                boolean certRequested;
357fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
358fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
359fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
360fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
361fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... over just wanting it...
363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
365fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
366fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
367fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
368fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else {
369fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = false;
370fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
371fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
372fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (certRequested) {
373fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
374fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
375fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
376fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        byte[][] issuersBytes;
377fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        try {
378fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
379fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        } catch (CertificateEncodingException e) {
380fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
381fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        }
382fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
383f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                    }
384f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
385f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
386f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
387fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
388fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int savedTimeoutMilliseconds = getSoTimeout();
389fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
390fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
391fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
393fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int sslSessionNativePointer;
394fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
395a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
396721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols);
397fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
398d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
399d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
400d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
4012828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
402fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
403fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
404fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (sslSession != null) {
405fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
406fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
407fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
408fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (!enableSessionCreation) {
409fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
410fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
411fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
412fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] localCertificates
413fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
414fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] peerCertificates
415fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
4163967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
4173967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
418fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
419fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (handshakeCompleted) {
420fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sessionContext.putSession(sslSession);
421fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
422f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            }
423fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
424fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
425fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
426fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(savedTimeoutMilliseconds);
427331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
42808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
429fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
430fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
431fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
432fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
433f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
434fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            exception = false;
4358765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        } catch (SSLProtocolException e) {
4368765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            throw new SSLHandshakeException(e);
437fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
438aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
439fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (exception) {
440aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom                close();
441fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
44208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
443e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
44408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4453967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    private String getPeerHostName() {
4468ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (wrappedHost != null) {
4478ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return wrappedHost;
4488ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4498ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        InetAddress inetAddress = super.getInetAddress();
4508ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (inetAddress != null) {
4518ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return inetAddress.getHostName();
4528ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4538ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        return null;
4543967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4553967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
4563967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    private int getPeerPort() {
4573967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
4583967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4593967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
460e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    /**
461e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * Return a possibly null array of X509Certificates given the
462e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * possibly null array of DER encoded bytes.
463e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     */
46490ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
465e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (certificatesBytes == null) {
466e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            return null;
467e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
468e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
469e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
470e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
471e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                certificates[i] = new X509CertImpl(certificatesBytes[i]);
472e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
473e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return null;
474e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
475e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
476e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        return certificates;
4772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
47808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
479f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
48098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (alias == null) {
48198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            return;
48298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
48398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
4848765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (privateKey == null) {
4858765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
4868765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
48798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
4888765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (certificates == null) {
4898765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
4908765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
4918765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom
492a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        if (privateKey instanceof OpenSSLRSAPrivateKey) {
493a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLRSAPrivateKey rsaKey = (OpenSSLRSAPrivateKey) privateKey;
494a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLKey key = rsaKey.getOpenSSLKey();
495a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
496a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        } else if (privateKey instanceof OpenSSLDSAPrivateKey) {
497a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLDSAPrivateKey dsaKey = (OpenSSLDSAPrivateKey) privateKey;
498a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLKey key = dsaKey.getOpenSSLKey();
499a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
500a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        } else if ("PKCS#8".equals(privateKey.getFormat())) {
501a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            byte[] privateKeyBytes = privateKey.getEncoded();
502a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
503a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        } else {
504a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            throw new SSLException("Unsupported PrivateKey format: " + privateKey.getFormat());
505a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        }
506a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root
507f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
50898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
50998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
51098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // checks the last installed private key and certificate,
51198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // so need to do this once per loop iteration
51298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
51398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
51498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5155006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
51698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
517f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
51898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
51998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
52098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
521ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
52298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
52398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
52498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        X500Principal[] issuers;
52598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        if (asn1DerEncodedPrincipals == null) {
52698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = null;
52798a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        } else {
52898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
52998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
53098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
53198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            }
53298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
53398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
53498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
53598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5365006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
5372828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void handshakeCompleted() {
5382828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        handshakeCompleted = true;
53908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5402828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // If sslSession is null, the handshake was completed during
5412828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5425006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // later read operation. That means we do not need to fix up
5432828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the SSLSession and session cache or notify
5442828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
5452828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // startHandshake.
5462828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (sslSession == null) {
5472828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return;
5482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
54908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5502828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
5512828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
5522828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
5532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
5542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
5552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
5562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
55708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
5582828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5592828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
5602828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
5612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
5622828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
5642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
5652828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
5662828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
5672828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
5682828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
5692828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
5702828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
5712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
572371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
573371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
574371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
575371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
576371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
577371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
578371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
5792828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
5802828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
5812828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
58208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
58308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5845006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
5855006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
58698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
58708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
588371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            if (bytes == null || bytes.length == 0) {
589371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
590371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
5912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
5922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
5936e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom                peerCertificateChain[i] = new X509CertImpl(bytes[i]);
59408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
5952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
5962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
59798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
59898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                                                                   authMethod);
5992828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
600ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
60198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
602ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                                                                   authType);
60308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
6052828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
6062828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
6073a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom        } catch (RuntimeException e) {
6083a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom            throw e;
6092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
6102828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw new RuntimeException(e);
61108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
61208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
61308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6145006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public InputStream getInputStream() throws IOException {
615a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
616f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
61708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
61808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
61908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
62008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
62108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return is;
62208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
62308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
62408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6255006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
626a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
627f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
62808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
62908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
63008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
63108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
63208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return os;
63308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
63408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
63508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6362828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
63708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
63808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
63908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
64008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
64108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
64208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLInputStream() throws IOException {
643d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            /*
644d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson             * Note: When startHandshake() throws an exception, no
64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             * SSLInputStream object will be created.
64608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
647d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
64808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
65008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
65208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * this operation can block until the data will be
65308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * available.
65408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @return read value.
65508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @throws <code>IOException</code>
65608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
65808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
6595c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            return Streams.readSingleByte(this);
66008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
66108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
66208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
66308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
66408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
66508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6660b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
66797e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
668ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
669f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6707b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
67197e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
67297e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
6737b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return 0;
6747b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
675a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
676a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
67808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
67908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
68008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
68108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
68208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
68308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
68408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
68508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
68608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
68708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLOutputStream() throws IOException {
688d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            /*
689d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson             * Note: When startHandshake() throws an exception, no
690f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom             * SSLOutputStream object will be created.
69108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
692d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson            OpenSSLSocketImpl.this.startHandshake();
69308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
69408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
69508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
69608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
69708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
69808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6990b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
7005c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom        public void write(int oneByte) throws IOException {
7015c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
70208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
70308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
70408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
70508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
70608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
70708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
70997e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
710ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
711f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7127b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
71397e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
71497e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
7157b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return;
7167b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
717a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
718a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount);
71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
72008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
72108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
72208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
72308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7245006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public SSLSession getSession() {
725e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
726e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
727d7f42443e3358023ee2848e4634a2f0ce11138e9Jesse Wilson                startHandshake();
728e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
729e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
730e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
731e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
732e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
73308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
73408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
73508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
73608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7375006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void addHandshakeCompletedListener(
73808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
73908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
74008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
74108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
74208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
7435006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
74408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
74608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
74708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7485006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void removeHandshakeCompletedListener(
74908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
75008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
75108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
75208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
75408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
75508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
75608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
75808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
75908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
76008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
76208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7635006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getEnableSessionCreation() {
76408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
76508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
76608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7675006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
76908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7715006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedCipherSuites() {
772f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
77308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7755006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledCipherSuites() {
7762828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledCipherSuites.clone();
77708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7795006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
7802828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7835006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedProtocols() {
784f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
78508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7875006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledProtocols() {
7882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledProtocols.clone();
78908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7915006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
7922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
79508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
7960b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods that may be used on this SSL
7970b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * connection.
7980b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
7990b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8000b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getSupportedCompressionMethods() {
8010b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return NativeCrypto.getSupportedCompressionMethods();
8020b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8030b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8040b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8050b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods versions that are in use
8060b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * on this SSL connection.
8070b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
8090b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8100b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getEnabledCompressionMethods() {
8110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return enabledCompressionMethods.clone();
8120b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8130b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8140b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8155006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Enables compression methods listed by getSupportedCompressionMethods().
8160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8170b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @throws IllegalArgumentException when one or more of the names in the
8180b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *             array are not supported, or when the array is null.
8190b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8205006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    public void setEnabledCompressionMethods(String[] methods) {
8210b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods);
8220b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8230b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8250b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
8260b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8270b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8280b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8290b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8300b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8310b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8320b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8330b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8340b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
8350b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8360b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8380b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
8390b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.hostname = hostname;
8400b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8410b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8425006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getUseClientMode() {
84308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
84408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
84508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8465006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setUseClientMode(boolean mode) {
84708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (handshakeStarted) {
84808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
8495006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                    "Could not change the mode after the initial handshake has begun.");
85008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
85108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
85208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
85308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8545006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getWantClientAuth() {
85508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
85608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
85708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8585006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getNeedClientAuth() {
85908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
86008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8625006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setNeedClientAuth(boolean need) {
86308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
86408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8665006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setWantClientAuth(boolean want) {
86708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
86808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8705006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
8715006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
87208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8745006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
8755006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
87608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8785006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
87972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        super.setSoTimeout(timeoutMilliseconds);
88072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.timeoutMilliseconds = timeoutMilliseconds;
88172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
88272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
8835006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public int getSoTimeout() throws SocketException {
88472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        return timeoutMilliseconds;
88508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
88608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
887331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
888331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
889331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
890331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
89172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
89272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
893331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
894331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
8955006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void close() throws IOException {
8965006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
89708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
89808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
89908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
9005006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                // prevent further attempts to start handshake
90108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
902f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
90308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (this) {
904f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
90508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
90690ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
90708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
90808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
90908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed()) super.close();
91008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
91108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
912f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
91308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
91408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
91508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
91608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
91708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (this) {
91808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
919fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            // Interrupt any outstanding reads or writes before taking the writeLock and readLock
920fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            NativeCrypto.SSL_interrupt(sslNativePointer);
9218b352156f879e7b36d223d3f65b8de46b7dc4dcfBrian Carlstrom
922fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom            synchronized (writeLock) {
923fa6657aaf2fadbb1aeb2f869cba82042c1faedeaBrian Carlstrom                synchronized (readLock) {
92408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    // Shut down the SSL connection, per se.
92508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    try {
92608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (handshakeStarted) {
927ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
928a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
929a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                                    this);
93008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        }
93186c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                    } catch (IOException ignored) {
93208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        /*
93386c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * Note that although close() can throw
93486c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * IOException, the RI does not throw if there
93586c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * is problem sending a "close notify" which
93686c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * can happen if the underlying socket is closed.
93708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                         */
93806327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                    } finally {
93906327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        /*
94006327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * Even if the above call failed, it is still safe to free
94106327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * the native structs, and we need to do so lest we leak
94206327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * memory.
94306327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         */
94406327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        free();
94506327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom
94606327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        if (socket != this) {
94706327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
94806327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                                socket.close();
94906327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            }
95006327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        } else {
95106327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            if (!super.isClosed()) {
95206327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                                super.close();
95306327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            }
95406327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        }
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    }
9960648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey
9970648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    @Override
9980648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
9990648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        if (socket == this) {
10000648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return super.getFileDescriptor$();
10010648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        } else {
10020648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return socket.getFileDescriptor$();
10030648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        }
10040648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    }
1005721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1006721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1007721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
1008721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocol was agreed upon.
1009721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1010721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public byte[] getNpnSelectedProtocol() {
1011263808a68e1538db41196065830107991e9f974aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
1012721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
1013721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1014721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1015721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Sets the list of protocols this peer is interested in. If null no
1016721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocols will be used.
1017721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *
1018d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     * @param npnProtocols a non-empty array of protocol names. From
1019d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     SSL_select_next_proto, "vector of 8-bit, length prefixed byte
1020d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     strings. The length byte itself is not included in the length. A byte
1021d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson     *     string of length 0 is invalid. No byte string may be truncated.".
1022721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1023721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
1024d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        if (npnProtocols != null && npnProtocols.length == 0) {
1025d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson            throw new IllegalArgumentException("npnProtocols.length == 0");
1026d38e01d8984d319fd8111193b9bf0fa14bbe1629Jesse Wilson        }
1027721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson        this.npnProtocols = npnProtocols;
1028721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
102908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
1030