OpenSSLSocketImpl.java revision a6d7bdeb041f42efd0cb441dea270b07debde421
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;
2190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstromimport 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;
37f7923f6b146ae1a750fb733cf03f9db27e68b5dacrazybobimport java.util.concurrent.atomic.AtomicInteger;
3808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport java.util.logging.Logger;
3908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedEvent;
4008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.HandshakeCompletedListener;
4108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLException;
42edc307bd5a7cf750852b9083ba203ba1c24fcdaeBrian Carlstromimport javax.net.ssl.SSLHandshakeException;
4308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Projectimport javax.net.ssl.SSLSession;
44fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstromimport javax.net.ssl.X509TrustManager;
4598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstromimport javax.security.auth.x500.X500Principal;
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>
5108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project * This class only supports SSLv3 and TLSv1. This should be documented elsewhere
52f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom * later, for example in the package.html or a separate reference document.
530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <p>
540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * Extensions to SSLSocket include:
550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <ul>
560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>handshake timeout
570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>compression methods
580b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>session tickets
590b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * <li>Server Name Indication
600b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom * </ul>
6108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project */
62f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrompublic class OpenSSLSocketImpl
63f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        extends javax.net.ssl.SSLSocket
6498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        implements NativeCrypto.SSLHandshakeCallbacks {
6590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom
66f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private int sslNativePointer;
6708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private InputStream is;
6808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OutputStream os;
6908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private final Object handshakeLock = new Object();
70f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object readLock = new Object();
71f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private final Object writeLock = new Object();
72cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private SSLParametersImpl sslParameters;
732828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private String[] enabledProtocols;
742828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private String[] enabledCipherSuites;
750b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private String[] enabledCompressionMethods;
760b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private boolean useSessionTickets;
770b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    private String hostname;
7808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private OpenSSLSessionImpl sslSession;
7990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private final Socket socket;
8008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private boolean autoClose;
8108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private boolean handshakeStarted = false;
82f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom    private final CloseGuard guard = CloseGuard.get();
832828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
842828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
852828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Not set to true until the update from native that tells us the
862828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * full handshake is complete, since SSL_do_handshake can return
872828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * before the handshake is completely done due to
882828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * handshake_cutthrough support.
892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
902828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private boolean handshakeCompleted = false;
912828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
9208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private ArrayList<HandshakeCompletedListener> listeners;
9372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
9472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    /**
9572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * Local cache of timeout to avoid getsockopt on every read and
9672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * write for non-wrapped sockets. Note that
9772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * OpenSSLSocketImplWrapper overrides setSoTimeout and
9872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     * getSoTimeout to delegate to the wrapped socket.
9972721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom     */
10072721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int timeoutMilliseconds = 0;
10172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
10272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    private int handshakeTimeoutMilliseconds = -1;  // -1 = same as timeout; 0 = infinite
1036e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom    private String wrappedHost;
1046e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom    private int wrappedPort;
10508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
10608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
10708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Class constructor with 1 parameter
10808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
10908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param sslParameters Parameters for the SSL
11008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *            context
11108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IOException if network fails
11208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
113cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters) throws IOException {
11490ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
115f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
11608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
11708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
11808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
1192828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Create an OpenSSLSocketImpl from an OpenSSLServerSocketImpl
1202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     *
1212828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @param sslParameters Parameters for the SSL
1222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     *            context
1232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @throws IOException if network fails
1242828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
125cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(SSLParametersImpl sslParameters,
1262828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                                String[] enabledProtocols,
1270b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                                String[] enabledCipherSuites,
1280b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                                String[] enabledCompressionMethods) throws IOException {
12990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
1300b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        init(sslParameters, enabledProtocols, enabledCipherSuites, enabledCompressionMethods);
1312828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
1322828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
1332828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
13408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Class constructor with 3 parameters
13508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
13608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IOException if network fails
13708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws java.net.UnknownHostException host not defined
13808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
139cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(String host, int port, SSLParametersImpl sslParameters)
14090ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
14108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port);
14290ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
143f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
14408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
14508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
14608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
14708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Class constructor with 3 parameters: 1st is InetAddress
14808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
14908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IOException if network fails
15008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws java.net.UnknownHostException host not defined
15108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
152cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    protected OpenSSLSocketImpl(InetAddress address, int port, SSLParametersImpl sslParameters)
15390ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
15408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port);
15590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
156f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
15708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
15808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
15908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
16008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
16108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Class constructor with 5 parameters: 1st is host
16208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
16308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IOException if network fails
16408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws java.net.UnknownHostException host not defined
16508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
166c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom    protected OpenSSLSocketImpl(String host, int port,
167c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
168cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom                                SSLParametersImpl sslParameters)
16990ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
17008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(host, port, clientAddress, clientPort);
17190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
172f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
17308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
17408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
17508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
17608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Class constructor with 5 parameters: 1st is InetAddress
17708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
17808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IOException if network fails
17908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws java.net.UnknownHostException host not defined
18008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
18108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(InetAddress address, int port,
182c7eac25a7d55812eaaecd8a8a5cdaac3a28b2bf5Brian Carlstrom                                InetAddress clientAddress, int clientPort,
183cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom                                SSLParametersImpl sslParameters)
18490ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom            throws IOException {
18508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        super(address, port, clientAddress, clientPort);
18690ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom        this.socket = this;
187f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
18808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
18908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
19008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
19108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Constructor with 5 parameters: 1st is socket. Enhances an existing socket
1926e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom     * with SSL functionality. Invoked via OpenSSLSocketImplWrapper constructor.
19308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
19408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IOException if network fails
19508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
19608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    protected OpenSSLSocketImpl(Socket socket, String host, int port,
197cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom            boolean autoClose, SSLParametersImpl sslParameters) throws IOException {
19808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.socket = socket;
1996e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedHost = host;
2006e0361de414915ae9929f55f6a8e0266a67506efBrian Carlstrom        this.wrappedPort = port;
20108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        this.autoClose = autoClose;
202f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        init(sslParameters);
20372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
20472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // this.timeout is not set intentionally.
20572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // OpenSSLSocketImplWrapper.getSoTimeout will delegate timeout
20672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        // to wrapped socket
207f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
208f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
209f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
210f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * Initialize the SSL socket and set the certificates for the
211f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * future handshaking.
212f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
213cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters) throws IOException {
2142828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        init(sslParameters,
2152828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom             NativeCrypto.getSupportedProtocols(),
2160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom             NativeCrypto.getDefaultCipherSuites(),
2170b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom             NativeCrypto.getDefaultCompressionMethods());
218f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
219f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
220f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    /**
2212828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Initialize the SSL socket and set the certificates for the
2222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * future handshaking.
223f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     */
224cbbd49c29da3e87cb7775ba789a0211cba0b909fBrian Carlstrom    private void init(SSLParametersImpl sslParameters,
2252828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                      String[] enabledProtocols,
2260b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                      String[] enabledCipherSuites,
2270b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                      String[] enabledCompressionMethods) throws IOException {
2282828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.sslParameters = sslParameters;
2292828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledProtocols = enabledProtocols;
2302828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        this.enabledCipherSuites = enabledCipherSuites;
2310b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.enabledCompressionMethods = enabledCompressionMethods;
23208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
23308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
23408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
23508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Gets the suitable session reference from the session cache container.
23608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
23708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return OpenSSLSessionImpl
23808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
2392828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private OpenSSLSessionImpl getCachedClientSession(ClientSessionContext sessionContext) {
24008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (super.getInetAddress() == null ||
24108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getInetAddress().getHostAddress() == null ||
24208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getInetAddress().getHostName() == null) {
24308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return null;
24408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
24561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession(
24608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getInetAddress().getHostName(),
24708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                super.getPort());
24861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (session == null) {
24961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
25061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
25161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
25261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String protocol = session.getProtocol();
25361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean protocolFound = false;
25461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledProtocol : enabledProtocols) {
25561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (protocol.equals(enabledProtocol)) {
25661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                protocolFound = true;
25761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
25861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
25961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
26061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!protocolFound) {
26161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
26261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
26361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom
26461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        String cipherSuite = session.getCipherSuite();
26561b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        boolean cipherSuiteFound = false;
26661b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        for (String enabledCipherSuite : enabledCipherSuites) {
26761b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            if (cipherSuite.equals(enabledCipherSuite)) {
26861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                cipherSuiteFound = true;
26961b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom                break;
27061b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            }
27161b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
27261b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        if (!cipherSuiteFound) {
27361b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom            return null;
27461b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        }
27598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
2760b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        String compressionMethod = session.getCompressionMethod();
2770b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        boolean compressionMethodFound = false;
2780b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        for (String enabledCompressionMethod : enabledCompressionMethods) {
2790b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            if (compressionMethod.equals(enabledCompressionMethod)) {
2800b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                compressionMethodFound = true;
2810b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom                break;
2820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            }
2830b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        }
2840b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        if (!compressionMethodFound) {
2850b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom            return null;
2860b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        }
2870b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
28861b2ada13329b7d1698f6c706b31077a67fbac2dBrian Carlstrom        return session;
28908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
29008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
29108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
29208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Ensures that logger is lazily loaded. The outer class seems to load
29308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * before logging is ready.
29408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
29508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    static class LoggerHolder {
296f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        static final Logger logger = Logger.getLogger(OpenSSLSocketImpl.class.getName());
29708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
29808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
29908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
30008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Starts a TLS/SSL handshake on this connection using some native methods
30108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * from the OpenSSL library. It can negotiate new encryption keys, change
30208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * cipher suites, or initiate a new session. The certificate chain is
30308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * verified if the correspondent property in java.Security is set. All
304f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     * listeners are notified at the end of the TLS/SSL handshake.
30508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
30608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws <code>IOException</code> if network fails
30708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
3080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
3092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void startHandshake() throws IOException {
3102828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        startHandshake(true);
3112828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
3122828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
3132828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
314a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom     * Checks whether the socket is closed, and throws an exception.
315a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom     *
316a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom     * @throws SocketException
317a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom     *             if the socket is closed.
318a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom     */
319a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    private void checkOpen() throws SocketException {
320a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        if (isClosed()) {
321a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom            throw new SocketException("Socket is closed");
322a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        }
323a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    }
324a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom
325a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom    /**
3262828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * Perform the handshake
3272828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @param full If true, disable handshake cutthrough for a fully synchronous handshake
3282828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
3292828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public synchronized void startHandshake(boolean full) throws IOException {
33008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
3317b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom            checkOpen();
33208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
33308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
33408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            } else {
33508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
33608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
33708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
33808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
33998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // note that this modifies the global seed, not something specific to the connection
34098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int seedLengthInBytes = NativeCrypto.RAND_SEED_LENGTH_IN_BYTES;
34198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final SecureRandom secureRandom = sslParameters.getSecureRandomMember();
34298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (secureRandom == null) {
34398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_load_file("/dev/urandom", seedLengthInBytes);
34498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        } else {
34598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            NativeCrypto.RAND_seed(secureRandom.generateSeed(seedLengthInBytes));
34698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
34798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
34898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final boolean client = sslParameters.getUseClientMode();
34998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
35098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        final int sslCtxNativePointer = (client) ?
35198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getClientSessionContext().sslCtxNativePointer :
35298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            sslParameters.getServerSessionContext().sslCtxNativePointer;
35398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
354fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        this.sslNativePointer = 0;
355fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        boolean exception = true;
356fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        try {
357fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
358fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            guard.open("close");
35998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
360fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup server certificates and private keys.
361fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // clients will receive a call back to request certificates.
362fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!client) {
363d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                Set<String> keyTypes = new HashSet<String>();
364d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String enabledCipherSuite : enabledCipherSuites) {
365aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) {
366aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                        continue;
367aeb3b48a69c2294ca657acd3e8b94c9879d78b61Brian Carlstrom                    }
368ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                    String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType();
369d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    if (keyType != null) {
370d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                        keyTypes.add(keyType);
371d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                    }
372d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                }
373d5eeb213edc60ad4c33f1cec353899ab0957dd25Brian Carlstrom                for (String keyType : keyTypes) {
374fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    try {
375fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
376fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       null,
377fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                                                       this));
378fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    } catch (CertificateEncodingException e) {
379fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        throw new IOException(e);
380fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    }
381f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
38298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            }
38398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
384fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledProtocols(sslNativePointer, enabledProtocols);
385fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            NativeCrypto.setEnabledCipherSuites(sslNativePointer, enabledCipherSuites);
386fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (enabledCompressionMethods.length != 0) {
387fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.setEnabledCompressionMethods(sslNativePointer,
388fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                          enabledCompressionMethods);
389fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
390fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (useSessionTickets) {
391fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_options(sslNativePointer, NativeCrypto.SSL_OP_NO_TICKET);
392fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
393fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (hostname != null) {
394fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_tlsext_host_name(sslNativePointer, hostname);
395fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
3962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
397fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            boolean enableSessionCreation = sslParameters.getEnableSessionCreation();
398fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (!enableSessionCreation) {
399fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_set_session_creation_enabled(sslNativePointer,
400fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                              enableSessionCreation);
4012828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
4022828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
403fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            AbstractSessionContext sessionContext;
404fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            OpenSSLSessionImpl session;
405fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
406fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // look for client session to reuse
407fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                ClientSessionContext clientSessionContext = sslParameters.getClientSessionContext();
408fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = clientSessionContext;
409fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                session = getCachedClientSession(clientSessionContext);
410fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (session != null) {
411fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_session(sslNativePointer,
412fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                 session.sslSessionNativePointer);
413fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
414f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            } else {
415fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sessionContext = sslParameters.getServerSessionContext();
416fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                session = null;
417f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
41898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
419fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // setup peer certificate verification
420fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client) {
421fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // TODO support for anonymous cipher would require us to
422fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // conditionally use SSL_VERIFY_NONE
423fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
424fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // needing client auth takes priority...
425fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                boolean certRequested = false;
426fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (sslParameters.getNeedClientAuth()) {
427fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
428fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER
429fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                | NativeCrypto.SSL_VERIFY_FAIL_IF_NO_PEER_CERT);
430fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
431fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... over just wanting it...
432fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else if (sslParameters.getWantClientAuth()) {
433fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    NativeCrypto.SSL_set_verify(sslNativePointer,
434fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                NativeCrypto.SSL_VERIFY_PEER);
435fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = true;
436fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // ... and it defaults properly so don't call SSL_set_verify in the common case.
437fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else {
438fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    certRequested = false;
439fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
440fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
441fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (certRequested) {
442fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509TrustManager trustManager = sslParameters.getTrustManager();
443fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    X509Certificate[] issuers = trustManager.getAcceptedIssuers();
444fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    if (issuers != null && issuers.length != 0) {
445fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        byte[][] issuersBytes;
446fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        try {
447fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            issuersBytes = NativeCrypto.encodeIssuerX509Principals(issuers);
448fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        } catch (CertificateEncodingException e) {
449fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                            throw new IOException("Problem encoding principals", e);
450fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        }
451fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        NativeCrypto.SSL_set_client_CA_list(sslNativePointer, issuersBytes);
452f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                    }
453f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom                }
454f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            }
455f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
456fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (client && full) {
457fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // we want to do a full synchronous handshake, so turn off cutthrough
458fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_clear_mode(sslNativePointer,
459fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                            NativeCrypto.SSL_MODE_HANDSHAKE_CUTTHROUGH);
460fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
461f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
462fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Temporarily use a different timeout for the handshake process
463fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int savedTimeoutMilliseconds = getSoTimeout();
464fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
465fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(handshakeTimeoutMilliseconds);
466fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
4672828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
468fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            int sslSessionNativePointer;
469fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            try {
470a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                sslSessionNativePointer = NativeCrypto.SSL_do_handshake(sslNativePointer,
471a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        socket.getFileDescriptor$(), this, getSoTimeout(), client);
472fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } catch (CertificateException e) {
473d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                SSLHandshakeException wrapper = new SSLHandshakeException(e.getMessage());
474d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                wrapper.initCause(e);
475d16f39c2d50864d40774c838e305c9510445bfe3Brian Carlstrom                throw wrapper;
4762828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
477fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer);
478fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId);
479fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (sslSession != null) {
480fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                sslSession.lastAccessedTime = System.currentTimeMillis();
481fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                LoggerHolder.logger.fine("Reused cached session for "
482fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                         + getInetAddress() + ".");
483fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                NativeCrypto.SSL_SESSION_free(sslSessionNativePointer);
484fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            } else {
485fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (!enableSessionCreation) {
486fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    // Should have been prevented by NativeCrypto.SSL_set_session_creation_enabled
487fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    throw new IllegalStateException("SSL Session may not be created");
488fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
489fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] localCertificates
490fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_certificate(sslNativePointer));
491fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                X509Certificate[] peerCertificates
492fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                        = createCertChain(NativeCrypto.SSL_get_peer_cert_chain(sslNativePointer));
493fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (wrappedHost == null) {
494fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
495fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        localCertificates, peerCertificates,
496fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        super.getInetAddress().getHostName(),
497fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        super.getPort(), sessionContext);
498fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                } else  {
499fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sslSession = new OpenSSLSessionImpl(sslSessionNativePointer,
500fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        localCertificates, peerCertificates,
501fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        wrappedHost, wrappedPort,
502fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                                        sessionContext);
503fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
504fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                // if not, putSession later in handshakeCompleted() callback
505fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                if (handshakeCompleted) {
506fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                    sessionContext.putSession(sslSession);
507fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                }
508fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                LoggerHolder.logger.fine("Created new session for "
509fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                                         + getInetAddress().getHostName() + ".");
510f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            }
511fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom
512fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // Restore the original timeout now that the handshake is complete
513fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeTimeoutMilliseconds >= 0) {
514fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                setSoTimeout(savedTimeoutMilliseconds);
515331900211d05cd282141a3a50cb1db626f418b2cDan Egnor            }
51608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
517fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            // if not, notifyHandshakeCompletedListeners later in handshakeCompleted() callback
518fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (handshakeCompleted) {
519fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom                notifyHandshakeCompletedListeners();
520fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
521f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
522fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            exception = false;
523fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        } finally {
524aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom            // on exceptional exit, treat the socket as closed
525fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            if (exception) {
526aef0b218983e04bc05ffb5746b4f452725f704b7Brian Carlstrom                close();
527fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom            }
52808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
529e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    }
53008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
531e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom    /**
532e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * Return a possibly null array of X509Certificates given the
533e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     * possibly null array of DER encoded bytes.
534e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom     */
53590ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom    private static X509Certificate[] createCertChain(byte[][] certificatesBytes) {
536e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (certificatesBytes == null) {
537e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            return null;
538e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
539e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        X509Certificate[] certificates = new X509Certificate[certificatesBytes.length];
540e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        for (int i = 0; i < certificatesBytes.length; i++) {
541e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
542e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                certificates[i] = new X509CertImpl(certificatesBytes[i]);
543e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
544e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return null;
545e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
546e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        }
547e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        return certificates;
5482828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
54908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
550f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom    private void setCertificate(String alias) throws CertificateEncodingException, SSLException {
55198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        if (alias == null) {
55298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            return;
55398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        }
55498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
55598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias);
5561f42e0a4d7d28b8fc20833e0be05ad17dcfa8ea0Brian Carlstrom        byte[] privateKeyBytes = privateKey.getEncoded();
55798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_use_PrivateKey(sslNativePointer, privateKeyBytes);
55898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
55998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias);
560f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        byte[][] certificateBytes = NativeCrypto.encodeCertificates(certificates);
56198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
56298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
56398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // checks the last installed private key and certificate,
56498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        // so need to do this once per loop iteration
56598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom        NativeCrypto.SSL_check_private_key(sslNativePointer);
56698ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
56798ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
56898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    /**
56998ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom     * Implementation of NativeCrypto.SSLHandshakeCallbacks
57098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom     * invoked via JNI from client_cert_cb
57198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom     */
57298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
573f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            throws CertificateEncodingException, SSLException {
57498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
57598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        String[] keyTypes = new String[keyTypeBytes.length];
57698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        for (int i = 0; i < keyTypeBytes.length; i++) {
577ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom            keyTypes[i] = CipherSuite.getClientKeyType(keyTypeBytes[i]);
57898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
57998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom
58098a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        X500Principal[] issuers;
58198a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        if (asn1DerEncodedPrincipals == null) {
58298a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = null;
58398a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        } else {
58498a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            issuers = new X500Principal[asn1DerEncodedPrincipals.length];
58598a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
58698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom                issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
58798a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom            }
58898a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        }
58998a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom        setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
59098ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    }
59198ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom
59208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
59398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom     * Implementation of NativeCrypto.SSLHandshakeCallbacks
5942828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * invoked via JNI from info_callback
59508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
5962828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    public void handshakeCompleted() {
5972828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        handshakeCompleted = true;
59808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
5992828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // If sslSession is null, the handshake was completed during
6002828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the call to NativeCrypto.SSL_do_handshake and not during a
6012828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // later read operation. That means we do not need to fixup
6022828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // the SSLSession and session cache or notify
6032828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // HandshakeCompletedListeners, it will be done in
6042828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // startHandshake.
6052828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (sslSession == null) {
6062828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            return;
6072828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
60808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
6092828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // reset session id from the native pointer and update the
6102828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // appropriate cache.
6112828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        sslSession.resetId();
6122828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        AbstractSessionContext sessionContext =
6132828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            (sslParameters.getUseClientMode())
6142828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            ? sslParameters.getClientSessionContext()
6152828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                : sslParameters.getServerSessionContext();
61608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sessionContext.putSession(sslSession);
6172828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
6182828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        // let listeners know we are finally done
6192828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        notifyHandshakeCompletedListeners();
6202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    }
6212828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
6222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    private void notifyHandshakeCompletedListeners() {
6232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        if (listeners != null && !listeners.isEmpty()) {
6242828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            // notify the listeners
6252828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            HandshakeCompletedEvent event =
6262828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                new HandshakeCompletedEvent(this, sslSession);
6272828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (HandshakeCompletedListener listener : listeners) {
6282828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                try {
6292828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                    listener.handshakeCompleted(event);
6302828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                } catch (RuntimeException e) {
631371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // The RI runs the handlers in a separate thread,
632371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // which we do not. But we try to preserve their
633371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // behavior of logging a problem and not killing
634371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // the handshaking thread just because a listener
635371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    // has a problem.
636371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    Thread thread = Thread.currentThread();
637371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                    thread.getUncaughtExceptionHandler().uncaughtException(thread, e);
6382828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                }
6392828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            }
6402828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        }
64108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
64208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
64308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
64498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom     * Implementation of NativeCrypto.SSLHandshakeCallbacks
645f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     *
64698a43fda08c8dae8b308fb91756fb121ec1c8ac2Brian Carlstrom     * @param bytes An array of ASN.1 DER encoded certficates
6472828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @param authMethod auth algorithm name
64808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
6492828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * @throws CertificateException if the certificate is untrusted
65008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
65108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @SuppressWarnings("unused")
65298ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom    public void verifyCertificateChain(byte[][] bytes, String authMethod)
65398ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom            throws CertificateException {
65408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        try {
655371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            if (bytes == null || bytes.length == 0) {
656371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom                throw new SSLException("Peer sent no certificate");
657371c4e83bab807ee4fd7ffab9d36a5f31a55dc46Brian Carlstrom            }
6582828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            X509Certificate[] peerCertificateChain = new X509Certificate[bytes.length];
6592828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            for (int i = 0; i < bytes.length; i++) {
6606e24f16869f652c340bb973069ec5fec21317137Brian Carlstrom                peerCertificateChain[i] = new X509CertImpl(bytes[i]);
66108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6622828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            boolean client = sslParameters.getUseClientMode();
6632828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            if (client) {
66498ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkServerTrusted(peerCertificateChain,
66598ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                                                                   authMethod);
6662828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            } else {
667ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                String authType = peerCertificateChain[0].getPublicKey().getAlgorithm();
66898ec0ef4090e2e7a2f98a9171140e549e2220cacBrian Carlstrom                sslParameters.getTrustManager().checkClientTrusted(peerCertificateChain,
669ea8732bc2631141874302bc25ee2795a89f4922fBrian Carlstrom                                                                   authType);
67008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
6712828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom
6722828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (CertificateException e) {
6732828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw e;
6742828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        } catch (Exception e) {
6752828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            throw new RuntimeException(e);
67608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
67708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
67808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
67908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
68008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Returns an input stream for this SSL socket using native calls to the
68108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * OpenSSL library.
68208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
68308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return: an input stream for reading bytes from this socket.
68408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws: <code>IOException</code> if an I/O error occurs when creating
68508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *          the input stream, the socket is closed, the socket is not
68608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *          connected, or the socket input has been shutdown.
68708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
6880b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
68908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public InputStream getInputStream() throws IOException {
690a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
691f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
69208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (is == null) {
69308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                is = new SSLInputStream();
69408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
69508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
69608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return is;
69708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
69808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
69908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
70008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
70108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Returns an output stream for this SSL socket using native calls to the
70208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * OpenSSL library.
70308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
70408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return an output stream for writing bytes to this socket.
70508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws <code>IOException</code> if an I/O error occurs when creating
70608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *             the output stream, or no connection to the socket exists.
70708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
7080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
70908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public OutputStream getOutputStream() throws IOException {
710a2770d6e45dd961b24543ffbde7fa41bd548e7e8Brian Carlstrom        checkOpen();
711f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom        synchronized (this) {
71208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (os == null) {
71308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                os = new SSLOutputStream();
71408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
71508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
71608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            return os;
71708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
71808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
71908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7202828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
7212828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * This method is not supported for this SSLSocket implementation
7222828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * because reading from an SSLSocket may involve writing to the
7232828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * network.
7242828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
7250b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
72608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void shutdownInput() throws IOException {
7272828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        throw new UnsupportedOperationException();
72808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
72908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
7302828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom    /**
7312828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * This method is not supported for this SSLSocket implementation
7322828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * because writing to an SSLSocket may involve reading from the
7332828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     * network.
7342828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom     */
7350b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
73608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void shutdownOutput() throws IOException {
7372828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        throw new UnsupportedOperationException();
73808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
73908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
74008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
74108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides input data stream functionality
74208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
74308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * read data received via SSL protocol.
74408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
74508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLInputStream extends InputStream {
74608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLInputStream() throws IOException {
74708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /**
74808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /* Note: When startHandshake() throws an exception, no
74908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             * SSLInputStream object will be created.
75008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
7512828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
75208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
75308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
75408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
75508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Reads one byte. If there is no data in the underlying buffer,
75608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * this operation can block until the data will be
75708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * available.
75808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @return read value.
75908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @throws <code>IOException</code>
76008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7610b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
76208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public int read() throws IOException {
763ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
764f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
7657b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
766a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read_byte(sslNativePointer, socket.getFileDescriptor$(),
767a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, getSoTimeout());
76808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
76908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
77008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
77108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
77208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
77308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.InputStream#read(byte[],int,int)
77408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
7750b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
77697e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public int read(byte[] buf, int offset, int byteCount) throws IOException {
777ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
778f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (readLock) {
7797b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
78097e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
78197e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
7827b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return 0;
7837b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
784a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                return NativeCrypto.SSL_read(sslNativePointer, socket.getFileDescriptor$(),
785a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount, getSoTimeout());
78608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
78708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
78808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
78908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
79008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
79108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This inner class provides output data stream functionality
79208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * for the OpenSSL native implementation. It is used to
79308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * write data according to the encryption parameters given in SSL context.
79408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
79508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    private class SSLOutputStream extends OutputStream {
79608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        SSLOutputStream() throws IOException {
79708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /**
79808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            /* Note: When startHandshake() throws an exception, no
799f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom             * SSLOutputStream object will be created.
80008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project             */
8012828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom            OpenSSLSocketImpl.this.startHandshake(false);
80208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
80308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
80408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
80508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
80608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(int)
80708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
8080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
80908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        public void write(int b) throws IOException {
810ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
811f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
8127b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
813a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write_byte(sslNativePointer, socket.getFileDescriptor$(),
814a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, b);
81508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
81608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
81708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
81808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        /**
81908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * Method acts as described in spec for superclass.
82008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         * @see java.io.OutputStream#write(byte[],int,int)
82108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project         */
8220b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        @Override
82397e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes        public void write(byte[] buf, int offset, int byteCount) throws IOException {
824ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick            BlockGuard.getThreadPolicy().onNetwork();
825f52606090f0f7160c2c7a85069959c1124151d79Brian Carlstrom            synchronized (writeLock) {
8267b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                checkOpen();
82797e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                Arrays.checkOffsetAndCount(buf.length, offset, byteCount);
82897e840f13f356fa77f9bf915e4b489df1feb4d80Elliott Hughes                if (byteCount == 0) {
8297b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                    return;
8307b155011296152295a987bc78f8dc7a3c5cc6ffbBrian Carlstrom                }
831a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                NativeCrypto.SSL_write(sslNativePointer, socket.getFileDescriptor$(),
832a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                        OpenSSLSocketImpl.this, buf, offset, byteCount);
83308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
83408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
83508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
83608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
83708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
83808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
83908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * The SSL session used by this connection is returned. The SSL session
84008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * determines which cipher suite should be used by all connections within
84108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * that session and which identities have the session's client and server.
84208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method starts the SSL handshake.
84308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return the SSLSession.
84408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws <code>IOException</code> if the handshake fails
84508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
8460b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
84708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public SSLSession getSession() {
848e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom        if (sslSession == null) {
849e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            try {
850e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                startHandshake(true);
851e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            } catch (IOException e) {
852e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // return an invalid session with
853e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
854e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom                return SSLSessionImpl.NULL_SESSION;
855e247367fbd5d5b0451c3b3e61e6dba37f27d49e1Brian Carlstrom            }
85608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
85708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslSession;
85808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
85908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
86008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
86108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Registers a listener to be notified that a SSL handshake
86208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * was successfully completed on this connection.
86308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws <code>IllegalArgumentException</code> if listener is null.
86408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
8650b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
86608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void addHandshakeCompletedListener(
86708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
86808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
86908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
87008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
87108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
87208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            listeners = new ArrayList();
87308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
87408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        listeners.add(listener);
87508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
87608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
87708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
87808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * The method removes a registered listener.
87908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IllegalArgumentException if listener is null or not registered
88008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
8810b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
88208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void removeHandshakeCompletedListener(
88308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            HandshakeCompletedListener listener) {
88408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listener == null) {
88508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException("Provided listener is null");
88608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
88708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (listeners == null) {
88808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
88908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
89008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
89108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (!listeners.remove(listener)) {
89208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
89308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    "Provided listener is not registered");
89408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
89508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
89608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
89708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
89808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Returns true if new SSL sessions may be established by this socket.
89908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
90008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return true if the session may be created; false if a session already
90108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *         exists and must be resumed.
90208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
9030b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
90408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public boolean getEnableSessionCreation() {
90508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getEnableSessionCreation();
90608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
90708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
90808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
90908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Set a flag for the socket to inhibit or to allow the creation of a new
91008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * SSL sessions. If the flag is set to false, and there are no actual
91108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * sessions to resume, then there will be no successful handshaking.
91208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
91308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param flag true if session may be created; false
91408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *            if a session already exists and must be resumed.
91508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
9160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
91708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void setEnableSessionCreation(boolean flag) {
91808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setEnableSessionCreation(flag);
91908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
92008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
92108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
92208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * The names of the cipher suites which could be used by the SSL connection
92308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * are returned.
92408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return an array of cipher suite names
92508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
9260b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
92708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public String[] getSupportedCipherSuites() {
928f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedCipherSuites();
92908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
93008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
93108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
93208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * The names of the cipher suites that are in use in the actual the SSL
93308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * connection are returned.
93408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
93508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return an array of cipher suite names
93608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
9370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
93808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public String[] getEnabledCipherSuites() {
9392828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledCipherSuites.clone();
94008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
94108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
94208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
94308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method enables the cipher suites listed by
94408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * getSupportedCipherSuites().
94508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
94608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param suites names of all the cipher suites to
94708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *            put on use
94808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IllegalArgumentException when one or more of the
94908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *             ciphers in array suites are not supported, or when the array
95008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *             is null.
95108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
9520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
95308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void setEnabledCipherSuites(String[] suites) {
9542828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites);
95508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
95608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
95708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
95808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * The names of the protocols' versions that may be used on this SSL
95908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * connection.
96008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return an array of protocols names
96108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
9620b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
96308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public String[] getSupportedProtocols() {
964f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        return NativeCrypto.getSupportedProtocols();
96508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
96608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
96708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
96808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * The names of the protocols' versions that are in use on this SSL
96908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * connection.
970f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     *
97108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return an array of protocols names
97208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
97308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
97408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public String[] getEnabledProtocols() {
9752828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        return enabledProtocols.clone();
97608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
97708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
97808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
97908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method enables the protocols' versions listed by
98008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * getSupportedProtocols().
981f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     *
9820b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param protocols The names of all the protocols to allow
983f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom     *
98408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IllegalArgumentException when one or more of the names in the
98508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *             array are not supported, or when the array is null.
98608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
98708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    @Override
9880b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setEnabledProtocols(String[] protocols) {
9892828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom        enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols);
99008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
99108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
99208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
9930b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods that may be used on this SSL
9940b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * connection.
9950b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
9960b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
9970b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getSupportedCompressionMethods() {
9980b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return NativeCrypto.getSupportedCompressionMethods();
9990b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10000b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10010b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
10020b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * The names of the compression methods versions that are in use
10030b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * on this SSL connection.
10040b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10050b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return an array of compression methods
10060b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
10070b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String[] getEnabledCompressionMethods() {
10080b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return enabledCompressionMethods.clone();
10090b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10100b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10110b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
10120b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables the compression method listed by
10130b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * getSupportedCompressionMethods().
10140b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param methods The names of all the compression methods to allow
10160b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10170b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @throws IllegalArgumentException when one or more of the names in the
10180b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *             array are not supported, or when the array is null.
10190b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
10200b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setEnabledCompressionMethods (String[] methods) {
10210b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods);
10220b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10230b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10240b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
10250b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables session ticket support.
10260b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10270b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param useSessionTickets True to enable session tickets
10280b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
10290b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseSessionTickets(boolean useSessionTickets) {
10300b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.useSessionTickets = useSessionTickets;
10310b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10320b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10330b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
10340b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method gives true back if the SSL socket is set to client mode.
10350b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10360b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return true if the socket should do the handshaking as client.
10370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
10380b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public boolean getUseSessionTickets() {
10390b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return useSessionTickets;
10400b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10410b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10420b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
10430b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method enables Server Name Indication
10440b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10450b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @param hostname the desired SNI hostname, or null to disable
10460b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
10470b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setHostname(String hostname) {
10480b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        this.hostname = hostname;
10490b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10500b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10510b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
10520b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * This method returns the current SNI hostname
10530b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     *
10540b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     * @return a host name if SNI is enabled, or null otherwise
10550b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom     */
10560b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public String getHostname() {
10570b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom        return hostname;
10580b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    }
10590b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom
10600b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    /**
106108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method gives true back if the SSL socket is set to client mode.
106208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
106308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return true if the socket should do the handshaking as client.
106408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
106508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public boolean getUseClientMode() {
106608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getUseClientMode();
106708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
106808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
106908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
107008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method set the actual SSL socket to client mode.
107108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
107208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param mode true if the socket starts in client
107308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *            mode
107408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws IllegalArgumentException if mode changes during
107508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *             handshake.
107608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
10770b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
10780b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    public void setUseClientMode(boolean mode) {
107908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        if (handshakeStarted) {
108008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            throw new IllegalArgumentException(
108108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            "Could not change the mode after the initial handshake has begun.");
108208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
108308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setUseClientMode(mode);
108408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
108508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
108608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
108708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Returns true if the SSL socket requests client's authentication. Relevant
108808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * only for server sockets!
108908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
109008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return true if client authentication is desired, false if not.
109108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
10920b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
109308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public boolean getWantClientAuth() {
109408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getWantClientAuth();
109508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
109608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
109708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
109808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Returns true if the SSL socket needs client's authentication. Relevant
109908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * only for server sockets!
110008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
110108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @return true if client authentication is desired, false if not.
110208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11030b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
110408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public boolean getNeedClientAuth() {
110508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        return sslParameters.getNeedClientAuth();
110608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
110708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
110808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
110908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Sets the SSL socket to use client's authentication. Relevant only for
111008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * server sockets!
111108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
111208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param need true if client authentication is
111308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *            desired, false if not.
111408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11150b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
111608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void setNeedClientAuth(boolean need) {
111708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setNeedClientAuth(need);
111808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
111908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
112008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
112108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Sets the SSL socket to use client's authentication. Relevant only for
112208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * server sockets! Notice that in contrast to setNeedClientAuth(..) this
112308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * method will continue the negotiation if the client decide not to send
112408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * authentication credentials.
112508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
112608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param want true if client authentication is
112708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *            desired, false if not.
112808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11290b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
113008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void setWantClientAuth(boolean want) {
113108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        sslParameters.setWantClientAuth(want);
113208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
113308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
113408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
113508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method is not supported for SSLSocket implementation.
113608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11370b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
113808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void sendUrgentData(int data) throws IOException {
113908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        throw new SocketException(
114008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                "Method sendUrgentData() is not supported.");
114108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
114208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
114308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
114408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * This method is not supported for SSLSocket implementation.
114508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11460b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
114708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void setOOBInline(boolean on) throws SocketException {
114808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        throw new SocketException(
114908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                "Methods sendUrgentData, setOOBInline are not supported.");
115008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
115108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
115208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
115308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Set the read timeout on this socket. The SO_TIMEOUT option, is specified
115408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * in milliseconds. The read operation will block indefinitely for a zero
115508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * value.
115608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
115708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @param timeout the read timeout value
115808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws SocketException if an error occurs setting the option
115908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11600b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
116172721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    public void setSoTimeout(int timeoutMilliseconds) throws SocketException {
116272721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        super.setSoTimeout(timeoutMilliseconds);
116372721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.timeoutMilliseconds = timeoutMilliseconds;
116472721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    }
116572721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom
116672721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    @Override
116772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    public int getSoTimeout() throws SocketException {
116872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        return timeoutMilliseconds;
116908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
117008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1171331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    /**
1172331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * Set the handshake timeout on this socket.  This timeout is specified in
1173331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * milliseconds and will be used only during the handshake process.
1174331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     *
1175331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     * @param timeout the handshake timeout value
1176331900211d05cd282141a3a50cb1db626f418b2cDan Egnor     */
117772721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom    public void setHandshakeTimeout(int timeoutMilliseconds) throws SocketException {
117872721fe761a086800a0e119bf6766d6c1ead0d94Brian Carlstrom        this.handshakeTimeoutMilliseconds = timeoutMilliseconds;
1179331900211d05cd282141a3a50cb1db626f418b2cDan Egnor    }
1180331900211d05cd282141a3a50cb1db626f418b2cDan Egnor
118108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    /**
118208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * Closes the SSL socket. Once closed, a socket is not available for further
118308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * use anymore under any circumstance. A new socket must be created.
118408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *
118508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     * @throws <code>IOException</code> if an I/O error happens during the
118608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     *             socket's closure.
118708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project     */
11880b26b4367f0af550809c12ecea934723f16e7393Brian Carlstrom    @Override
118908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    public void close() throws IOException {
119008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        // TODO: Close SSL sockets using a background thread so they close
119108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        // gracefully.
119208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
119308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (handshakeLock) {
119408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            if (!handshakeStarted) {
11952828ed800862c0ed2cf2116cb986d6bf209e4f58Brian Carlstrom                // prevent further attemps to start handshake
119608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                handshakeStarted = true;
1197f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
119808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (this) {
1199f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
120008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
120190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
120208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed()) socket.close();
120308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
120408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed()) super.close();
120508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
120608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
1207f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom
120808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                return;
120908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
121008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
121108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
121258a44774b954fed596ee22307a231de783ea8121Brian Carlstrom        NativeCrypto.SSL_interrupt(sslNativePointer);
121308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
121408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        synchronized (this) {
121508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            synchronized (writeLock) {
121608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                synchronized (readLock) {
121708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
121808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    // Shut down the SSL connection, per se.
121908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    try {
122008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (handshakeStarted) {
1221ed2760e0dea39695b164af6d07ea9860e7c1fa49Brad Fitzpatrick                            BlockGuard.getThreadPolicy().onNetwork();
1222a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                            NativeCrypto.SSL_shutdown(sslNativePointer, socket.getFileDescriptor$(),
1223a6d7bdeb041f42efd0cb441dea270b07debde421Elliott Hughes                                    this);
122408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        }
122586c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                    } catch (IOException ignored) {
122608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        /*
122786c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * Note that although close() can throw
122886c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * IOException, the RI does not throw if there
122986c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * is problem sending a "close notify" which
123086c4c40d26570c38297cb78c47f437f79ca583b4Brian Carlstrom                         * can happen if the underlying socket is closed.
123108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                         */
123208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
123308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
123408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    /*
123508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     * Even if the above call failed, it is still safe to free
123608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     * the native structs, and we need to do so lest we leak
123708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     * memory.
123808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                     */
1239f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom                    free();
124008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
124190ed0ad55227df7a127054b25a43dbb6f6265a4bBrian Carlstrom                    if (socket != this) {
124208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (autoClose && !socket.isClosed())
124308ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                            socket.close();
124408ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    } else {
124508ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                        if (!super.isClosed())
124608ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                            super.close();
124708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                    }
124808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project                }
124908ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project            }
125008ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project        }
125108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
125208ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
1253f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    private void free() {
1254f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        if (sslNativePointer == 0) {
1255f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom            return;
1256f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        }
1257f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        NativeCrypto.SSL_free(sslNativePointer);
1258f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom        sslNativePointer = 0;
1259fce103dcb8270a7a4daa08c975e7e0bddf4ec67eBrian Carlstrom        guard.close();
1260f0c622f8ceb1fa261b67e3b8654f58254a12729cBrian Carlstrom    }
126108ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project
12621990574e420184f3ad43400171f624dad44700d8Brian Carlstrom    @Override protected void finalize() throws Throwable {
12631990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        try {
12641990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            /*
12651990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * Just worry about our own state. Notably we do not try and
12661990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * close anything. The SocketImpl, either our own
12671990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * PlainSocketImpl, or the Socket we are wrapping, will do
12681990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * that. This might mean we do not properly SSL_shutdown, but
12691990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * if you want to do that, properly close the socket yourself.
12701990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             *
12711990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * The reason why we don't try to SSL_shutdown, is that there
12721990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * can be a race between finalizers where the PlainSocketImpl
12731990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * finalizer runs first and closes the socket. However, in the
12741990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * meanwhile, the underlying file descriptor could be reused
12751990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * for another purpose. If we call SSL_shutdown, the
12761990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * underlying socket BIOs still have the old file descriptor
12771990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * and will write the close notify to some unsuspecting
12781990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             * reader.
12791990574e420184f3ad43400171f624dad44700d8Brian Carlstrom             */
1280f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            if (guard != null) {
1281f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom                guard.warnIfOpen();
1282f014c05bd5f8dbda1f5774755aefe54d546a297bBrian Carlstrom            }
12831990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            free();
12841990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        } finally {
12851990574e420184f3ad43400171f624dad44700d8Brian Carlstrom            super.finalize();
12861990574e420184f3ad43400171f624dad44700d8Brian Carlstrom        }
128708ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project    }
128808ecc8c0f00f1a7f2258c569187e36606ed73045The Android Open Source Project}
1289