OpenSSLSocketImpl.java revision 263808a68e1538db41196065830107991e9f974a
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,
1712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom             NativeCrypto.getSupportedProtocols(),
1720b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom             NativeCrypto.getDefaultCipherSuites(),
1730b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom             NativeCrypto.getDefaultCompressionMethods());
174f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
175f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
176f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
1772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
1782828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * future handshaking.
179f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
180cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters,
1812828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                      String[] enabledProtocols,
1820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                      String[] enabledCipherSuites,
1830b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                      String[] enabledCompressionMethods) throws IOException {
1842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.sslParameters = sslParameters;
1852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledProtocols = enabledProtocols;
1862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
1870b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.enabledCompressionMethods = enabledCompressionMethods;
18808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
18908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
19108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Gets the suitable session reference from the session cache container.
19208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
1932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
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
24508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
24608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Starts a TLS/SSL handshake on this connection using some native methods
24708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * from the OpenSSL library. It can negotiate new encryption keys, change
24808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * cipher suites, or initiate a new session. The certificate chain is
24908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * verified if the correspondent property in java.Security is set. All
250f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * listeners are notified at the end of the TLS/SSL handshake.
25108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
2520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
2532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void startHandshake() throws IOException {
2542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        startHandshake(true);
2552828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
2562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
257a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
258a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
259a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
260a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
261a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
262a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
263a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
2642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Perform the handshake
2655006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     *
2662828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @param full If true, disable handshake cutthrough for a fully synchronous handshake
2672828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
2682828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public synchronized void startHandshake(boolean full) throws IOException {
26908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
2707b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom            checkOpen();
27108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
27208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
27308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
27408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
27508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
27608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
27708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
27898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
27998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
28098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
28198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
28298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
28398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
28498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
28598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
28698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
28798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
28898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
28998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int sslCtxNativePointer = (client) ?
29098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
29198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
29298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
293fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        this.sslNativePointer = 0;
294fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        boolean exception = true;
295fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
296fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
297fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
29898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
299721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson            if (npnProtocols != null) {
300721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson                NativeCrypto.SSL_CTX_enable_npn(sslCtxNativePointer);
301721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson            }
302721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
303fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup server certificates and private keys.
304fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // clients will receive a call back to request certificates.
305fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!client) {
306d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
307d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
308aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
309aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                        continue;
310aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    }
311ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
312d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    if (keyType != null) {
313d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                        keyTypes.add(keyType);
314d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    }
315d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                }
316d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String keyType : keyTypes) {
317fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    try {
318fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
319fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       null,
320fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       this));
321fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    } catch (CertificateEncodingException e) {
322fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        throw new IOException(e);
323fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    }
324f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
32598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            }
32698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
327fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
328fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
329fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (enabledCompressionMethods.length != 0) {
330fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.setEnabledCompressionMethods(sslNativePointer,
331fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                          enabledCompressionMethods);
332fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
333fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (useSessionTickets) {
334fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
335fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
336fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (hostname != null) {
337fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
338fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3392828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
340fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
341fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
342fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
343fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                              enableSessionCreation);
3442828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
3452828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
346fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            AbstractSessionContext sessionContext;
347fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
348fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // look for client session to reuse
349fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
350fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = clientSessionContext;
3515006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                OpenSSLSessionImpl session = getCachedClientSession(clientSessionContext);
352fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (session != null) {
353fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
354fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                 session.sslSessionNativePointer);
355fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
356f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            } else {
357fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
358f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
35998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
360fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup peer certificate verification
361fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // TODO support for anonymous cipher would require us to
363fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
364fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
365fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // needing client auth takes priority...
3665006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                boolean certRequested;
367fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
368fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
369fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
370fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
371fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
372fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... over just wanting it...
373fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
374fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
375fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
376fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
377fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
378fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else {
379fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = false;
380fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
381fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
382fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (certRequested) {
383fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
384fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
385fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
386fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        byte[][] issuersBytes;
387fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        try {
388fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
389fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        } catch (CertificateEncodingException e) {
390fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
391fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        }
392fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
393f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                    }
394f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
395f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
396f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
397fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client && full) {
398fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // we want to do a full synchronous handshake, so turn off cutthrough
399fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_mode(sslNativePointer,
400fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                            NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
401fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
402f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
403fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
404fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int savedTimeoutMilliseconds = getSoTimeout();
405fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
406fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
407fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
4082828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
409fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int sslSessionNativePointer;
410fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
411a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
412721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson                        socket.getFileDescriptor$(), this, getSoTimeout(), client, npnProtocols);
413fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
414d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
415d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
416d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
4172828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
418fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
419fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
420fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (sslSession != null) {
421fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
422fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
423fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
424fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (!enableSessionCreation) {
425fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
426fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
427fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
428fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] localCertificates
429fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
430fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] peerCertificates
431fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
4323967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                sslSession = new OpenSSLSessionImpl(sslSessionNativePointer, localCertificates,
4333967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson                        peerCertificates, getPeerHostName(), getPeerPort(), sessionContext);
434fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
435fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (handshakeCompleted) {
436fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sessionContext.putSession(sslSession);
437fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
438f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            }
439fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
440fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
441fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
442fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(savedTimeoutMilliseconds);
443331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
44408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
445fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
446fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
447fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
448fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
449f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
450fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            exception = false;
4518765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        } catch (SSLProtocolException e) {
4528765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            throw new SSLHandshakeException(e);
453fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
454aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
455fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (exception) {
456aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom                close();
457fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
45808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
459e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
46008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
4613967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    private String getPeerHostName() {
4628ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (wrappedHost != null) {
4638ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return wrappedHost;
4648ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4658ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        InetAddress inetAddress = super.getInetAddress();
4668ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        if (inetAddress != null) {
4678ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom            return inetAddress.getHostName();
4688ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        }
4698ca27778bfc34425a4b13ca3090dd517dd61519eBrian Carlstrom        return null;
4703967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4713967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
4723967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    private int getPeerPort() {
4733967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson        return wrappedHost == null ? super.getPort() : wrappedPort;
4743967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson    }
4753967cef89302e18c0a651f7d90f4813ec2c1dc59Jesse Wilson
476e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    /**
477e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * Return a possibly null array of X509Certificates given the
478e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * possibly null array of DER encoded bytes.
479e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     */
48090ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
481e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (certificatesBytes == null) {
482e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            return null;
483e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
484e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
485e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
486e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
487e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                certificates[i] = new X509CertImpl(certificatesBytes[i]);
488e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
489e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return null;
490e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
491e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
492e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        return certificates;
4932828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
49408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
495f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
49698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (alias == null) {
49798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            return;
49898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
49998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
5008765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (privateKey == null) {
5018765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
5028765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
50398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
5048765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        if (certificates == null) {
5058765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom            return;
5068765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom        }
5078765df62ff836a2c4ee8b956945c38ba017cf309Brian Carlstrom
508a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        if (privateKey instanceof OpenSSLRSAPrivateKey) {
509a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLRSAPrivateKey rsaKey = (OpenSSLRSAPrivateKey) privateKey;
510a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLKey key = rsaKey.getOpenSSLKey();
511a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
512a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        } else if (privateKey instanceof OpenSSLDSAPrivateKey) {
513a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLDSAPrivateKey dsaKey = (OpenSSLDSAPrivateKey) privateKey;
514a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            OpenSSLKey key = dsaKey.getOpenSSLKey();
515a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            NativeCrypto.SSL_use_OpenSSL_PrivateKey(sslNativePointer, key.getPkeyContext());
516a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        } else if ("PKCS#8".equals(privateKey.getFormat())) {
517a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            byte[] privateKeyBytes = privateKey.getEncoded();
518a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
519a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        } else {
520a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root            throw new SSLException("Unsupported PrivateKey format: " + privateKey.getFormat());
521a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root        }
522a590ec8553482f097f10c5cb6dfaa4d44bdda1a0Kenny Root
523f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
52498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
52598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
52698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // checks the last installed private key and certificate,
52798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // so need to do this once per loop iteration
52898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
52998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
53098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5315006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / client_cert_cb
53298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
533f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
53498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
53598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
53698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
537ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
53898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
53998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
54098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        X500Principal[] issuers;
54198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        if (asn1DerEncodedPrincipals == null) {
54298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = null;
54398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        } else {
54498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
54598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
54698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
54798a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            }
54898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
54998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
55098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
55198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
5525006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks / info_callback
5532828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void handshakeCompleted() {
5542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        handshakeCompleted = true;
55508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5562828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // If sslSession is null, the handshake was completed during
5572828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
5585006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // later read operation. That means we do not need to fix up
5592828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the SSLSession and session cache or notify
5602828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
5612828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // startHandshake.
5622828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (sslSession == null) {
5632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return;
5642828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
56508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5662828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
5672828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
5682828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
5692828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
5702828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
5712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
5722828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
57308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
5742828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5752828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
5762828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
5772828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
5782828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
5792828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
5802828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
5812828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
5822828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
5832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
5842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
5852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
5862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
5872828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
588371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
589371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
590371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
591371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
592371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
593371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
594371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
5952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
5962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
5972828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
59808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
59908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6005006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @SuppressWarnings("unused") // used by NativeCrypto.SSLHandshakeCallbacks
6015006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void verifyCertificateChain(byte[][] bytes, String authMethod)
60298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
60308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
604371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            if (bytes == null || bytes.length == 0) {
605371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
606371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
6072828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
6082828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
6096e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom                peerCertificateChain[i] = new X509CertImpl(bytes[i]);
61008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6112828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
6122828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
61398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
61498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                                                                   authMethod);
6152828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
616ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
61798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
618ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                                                                   authType);
61908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
6212828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
6222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
6233a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom        } catch (RuntimeException e) {
6243a246337af275463275e608f6bd6f48b57322aacBrian Carlstrom            throw e;
6252828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
6262828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw new RuntimeException(e);
62708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
62808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
62908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6305006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public InputStream getInputStream() throws IOException {
631a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
632f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
63308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
63408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
63508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
63608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
63708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return is;
63808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
63908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
64008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6415006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public OutputStream getOutputStream() throws IOException {
642a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
643f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
64408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
64508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
64608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
64708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
64808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return os;
64908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
65008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6522828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
65308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
65408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
65508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
65608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
65708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
65808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLInputStream() throws IOException {
65908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /**
66008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /* Note: When startHandshake() throws an exception, no
66108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             * SSLInputStream object will be created.
66208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
6632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
66408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
66508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
66608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
66708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
66808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * this operation can block until the data will be
66908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * available.
67008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @return read value.
67108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @throws <code>IOException</code>
67208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6730b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
67408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
6755c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            return Streams.readSingleByte(this);
67608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
67808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
67908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
68008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
68108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
6820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
68397e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
684ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
685f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
6867b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
68797e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
68897e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
6897b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return 0;
6907b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
691a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
692a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
69308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
69408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
69508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
69608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
69708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
69808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
69908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
70008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
70108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
70208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
70308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLOutputStream() throws IOException {
70408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /**
70508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /* Note: When startHandshake() throws an exception, no
706f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom             * SSLOutputStream object will be created.
70708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
7082828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
70908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
71008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
71108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
71208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
71308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
71408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
7165c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom        public void write(int oneByte) throws IOException {
7175c44d1fc26c081cf85af010b6e751449bde14b80Brian Carlstrom            Streams.writeSingleByte(this, oneByte);
71808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
72008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
72108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
72208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
72308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
72597e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
726ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
727f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
7287b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
72997e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
73097e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
7317b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return;
7327b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
733a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
734a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount);
73508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
73608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
73708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
73808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
73908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7405006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public SSLSession getSession() {
741e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
742e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
743e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                startHandshake(true);
744e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
745e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
746e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
747e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
748e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
74908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
75108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
75208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7535006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void addHandshakeCompletedListener(
75408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
75508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
75608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
75708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
7595006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson            listeners = new ArrayList<HandshakeCompletedListener>();
76008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
76208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
76308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7645006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void removeHandshakeCompletedListener(
76508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
76608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
76708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
76908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
77008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
77108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
77208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
77308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
77408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
77508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
77608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
77708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
77808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7795006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getEnableSessionCreation() {
78008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
78108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7835006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnableSessionCreation(boolean flag) {
78408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
78508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7875006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedCipherSuites() {
788f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
78908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7915006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledCipherSuites() {
7922828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledCipherSuites.clone();
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7955006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledCipherSuites(String[] suites) {
7962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
79708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
79808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7995006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getSupportedProtocols() {
800f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
80108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
80208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8035006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public String[] getEnabledProtocols() {
8042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledProtocols.clone();
80508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
80608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8075006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setEnabledProtocols(String[] protocols) {
8082828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
80908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
81008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
81108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
8120b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods that may be used on this SSL
8130b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * connection.
8140b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
8150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getSupportedCompressionMethods() {
8170b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return NativeCrypto.getSupportedCompressionMethods();
8180b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8190b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8200b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8210b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods versions that are in use
8220b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * on this SSL connection.
8230b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
8250b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8260b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getEnabledCompressionMethods() {
8270b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return enabledCompressionMethods.clone();
8280b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8290b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8300b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8315006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson     * Enables compression methods listed by getSupportedCompressionMethods().
8320b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8330b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @throws IllegalArgumentException when one or more of the names in the
8340b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *             array are not supported, or when the array is null.
8350b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8365006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    public void setEnabledCompressionMethods(String[] methods) {
8370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods);
8380b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8390b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8400b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8410b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
8420b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8430b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
8440b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8450b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
8460b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.useSessionTickets = useSessionTickets;
8470b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8480b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8490b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
8500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
8510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
8520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
8530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
8540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
8550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.hostname = hostname;
8560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
8570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
8585006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getUseClientMode() {
85908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
86008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8625006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setUseClientMode(boolean mode) {
86308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (handshakeStarted) {
86408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
8655006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                    "Could not change the mode after the initial handshake has begun.");
86608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
86708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
86808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
86908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8705006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getWantClientAuth() {
87108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
87208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8745006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public boolean getNeedClientAuth() {
87508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
87608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8785006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setNeedClientAuth(boolean need) {
87908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
88008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
88108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8825006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setWantClientAuth(boolean want) {
88308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
88408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
88508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8865006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void sendUrgentData(int data) throws IOException {
8875006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Method sendUrgentData() is not supported.");
88808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
88908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8905006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setOOBInline(boolean on) throws SocketException {
8915006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        throw new SocketException("Methods sendUrgentData, setOOBInline are not supported.");
89208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
89308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
8945006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
89572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        super.setSoTimeout(timeoutMilliseconds);
89672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.timeoutMilliseconds = timeoutMilliseconds;
89772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
89872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
8995006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public int getSoTimeout() throws SocketException {
90072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        return timeoutMilliseconds;
90108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
90208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
903331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
904331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
905331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
906331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
90772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
90872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
909331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
910331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
9115006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson    @Override public void close() throws IOException {
9125006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson        // TODO: Close SSL sockets using a background thread so they close gracefully.
91308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
91408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
91508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
9165006f3bedbfd19dc905416bbf28bb0e95807f845Jesse Wilson                // prevent further attempts to start handshake
91708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
918f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
91908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (this) {
920f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
92108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
92290ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
92308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
92408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
92508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed()) super.close();
92608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
92708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
928f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
92908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
93008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
93108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
93208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
93358a44774b954fed596ee22307a231de783ea8121Brian Carlstrom        NativeCrypto.SSL_interrupt(sslNativePointer);
93408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
93508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (this) {
93608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            synchronized (writeLock) {
93708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (readLock) {
93808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
93908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    // Shut down the SSL connection, per se.
94008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    try {
94108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (handshakeStarted) {
942ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
943a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
944a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                                    this);
94508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        }
94686c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                    } catch (IOException ignored) {
94708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        /*
94886c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * Note that although close() can throw
94986c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * IOException, the RI does not throw if there
95086c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * is problem sending a "close notify" which
95186c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * can happen if the underlying socket is closed.
95208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                         */
95306327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                    } finally {
95406327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        /*
95506327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * Even if the above call failed, it is still safe to free
95606327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * the native structs, and we need to do so lest we leak
95706327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         * memory.
95806327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                         */
95906327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        free();
96006327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom
96106327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        if (socket != this) {
96206327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            if (autoClose && !socket.isClosed()) {
96306327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                                socket.close();
96406327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            }
96506327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        } else {
96606327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            if (!super.isClosed()) {
96706327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                                super.close();
96806327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                            }
96906327ec5e153c05a0e50df73093136d329038dafBrian Carlstrom                        }
97008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
97108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
97208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
97308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
97408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
97508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
976f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private void free() {
977f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        if (sslNativePointer == 0) {
978f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            return;
979f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        }
980f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
981f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        sslNativePointer = 0;
982fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        guard.close();
983f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
98408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
9851990574e420184f3ad43400171f624dad44700d8Brian Carlstrom    @Override protected void finalize() throws Throwable {
9861990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
9871990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            /*
9881990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * Just worry about our own state. Notably we do not try and
9891990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * close anything. The SocketImpl, either our own
9901990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
9911990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
9921990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * if you want to do that, properly close the socket yourself.
9931990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             *
9941990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
9951990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
9961990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
9971990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
9981990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
9991990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
10001990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * and will write the close notify to some unsuspecting
10011990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * reader.
10021990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             */
1003f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            if (guard != null) {
1004f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom                guard.warnIfOpen();
1005f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            }
10061990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            free();
10071990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
10081990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
10091990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
101008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
10110648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey
10120648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    @Override
10130648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    public FileDescriptor getFileDescriptor$() {
10140648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        if (socket == this) {
10150648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return super.getFileDescriptor$();
10160648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        } else {
10170648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey            return socket.getFileDescriptor$();
10180648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey        }
10190648ecb2d61dbe9dcf30ca39c366efd20266bfb3Jeff Sharkey    }
1020721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1021721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1022721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Returns the protocol agreed upon by client and server, or null if no
1023721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocol was agreed upon.
1024721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1025721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public byte[] getNpnSelectedProtocol() {
1026263808a68e1538db41196065830107991e9f974aJesse Wilson        return NativeCrypto.SSL_get_npn_negotiated_protocol(sslNativePointer);
1027721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
1028721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson
1029721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    /**
1030721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * Sets the list of protocols this peer is interested in. If null no
1031721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * protocols will be used.
1032721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *
1033721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     * @param npnProtocols from SSL_select_next_proto, "vector of 8-bit, length
1034721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *     prefixed byte strings. The length byte itself is not included in the
1035721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *     length. A byte string of length 0 is invalid. No byte string may be
1036721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     *     truncated.
1037721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson     */
1038721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    public void setNpnProtocols(byte[] npnProtocols) {
1039721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson        this.npnProtocols = npnProtocols;
1040721140f48732cec475e33af1e780fd325d1f8f6eJesse Wilson    }
104108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
1042