2493 lines · 91.5 KB · Java
RawDownload
/* * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */  package sun.security.ssl; import java.io.*;import java.net.*;import java.security.GeneralSecurityException;import java.security.AccessController;import java.security.AccessControlContext;import java.security.PrivilegedAction;import java.security.AlgorithmConstraints;import java.util.*;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReentrantLock; import javax.crypto.BadPaddingException; import javax.net.ssl.*; import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; /** * Implementation of an SSL socket.  This is a normal connection type * socket, implementing SSL over some lower level socket, such as TCP. * Because it is layered over some lower level socket, it MUST override * all default socket methods. * * <P> This API offers a non-traditional option for establishing SSL * connections.  You may first establish the connection directly, then pass * that connection to the SSL socket constructor with a flag saying which * role should be taken in the handshake protocol.  (The two ends of the * connection must not choose the same role!)  This allows setup of SSL * proxying or tunneling, and also allows the kind of "role reversal" * that is required for most FTP data transfers. * * @see javax.net.ssl.SSLSocket * @see SSLServerSocket * * @author David Brownell */final public class SSLSocketImpl extends BaseSSLSocketImpl {     /*     * ERROR HANDLING GUIDELINES     * (which exceptions to throw and catch and which not to throw and catch)     *     * . if there is an IOException (SocketException) when accessing the     *   underlying Socket, pass it through     *     * . do not throw IOExceptions, throw SSLExceptions (or a subclass)     *     * . for internal errors (things that indicate a bug in JSSE or a     *   grossly misconfigured J2RE), throw either an SSLException or     *   a RuntimeException at your convenience.     *     * . handshaking code (Handshaker or HandshakeMessage) should generally     *   pass through exceptions, but can handle them if they know what to     *   do.     *     * . exception chaining should be used for all new code. If you happen     *   to touch old code that does not use chaining, you should change it.     *     * . there is a top level exception handler that sits at all entry     *   points from application code to SSLSocket read/write code. It     *   makes sure that all errors are handled (see handleException()).     *     * . JSSE internal code should generally not call close(), call     *   closeInternal().     */     /*     * There's a state machine associated with each connection, which     * among other roles serves to negotiate session changes.     *     * - START with constructor, until the TCP connection's around.     * - HANDSHAKE picks session parameters before allowing traffic.     *          There are many substates due to sequencing requirements     *          for handshake messages.     * - DATA may be transmitted.     * - RENEGOTIATE state allows concurrent data and handshaking     *          traffic ("same" substates as HANDSHAKE), and terminates     *          in selection of new session (and connection) parameters     * - ERROR state immediately precedes abortive disconnect.     * - SENT_CLOSE sent a close_notify to the peer. For layered,     *          non-autoclose socket, must now read close_notify     *          from peer before closing the connection. For nonlayered or     *          non-autoclose socket, close connection and go onto     *          cs_CLOSED state.     * - CLOSED after sending close_notify alert, & socket is closed.     *          SSL connection objects are not reused.     * - APP_CLOSED once the application calls close(). Then it behaves like     *          a closed socket, e.g.. getInputStream() throws an Exception.     *     * State affects what SSL record types may legally be sent:     *     * - Handshake ... only in HANDSHAKE and RENEGOTIATE states     * - App Data ... only in DATA and RENEGOTIATE states     * - Alert ... in HANDSHAKE, DATA, RENEGOTIATE     *     * Re what may be received:  same as what may be sent, except that     * HandshakeRequest handshaking messages can come from servers even     * in the application data state, to request entry to RENEGOTIATE.     *     * The state machine within HANDSHAKE and RENEGOTIATE states controls     * the pending session, not the connection state, until the change     * cipher spec and "Finished" handshake messages are processed and     * make the "new" session become the current one.     *     * NOTE: details of the SMs always need to be nailed down better.     * The text above illustrates the core ideas.     *     *                +---->-------+------>--------->-------+     *                |            |                        |     *     <-----<    ^            ^  <-----<               v     *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE  SENT_CLOSE     *                v            v               v        |   |     *                |            |               |        |   v     *                +------------+---------------+        v ERROR     *                |                                     |   |     *                v                                     |   |     *               ERROR>------>----->CLOSED<--------<----+-- +     *                                     |     *                                     v     *                                 APP_CLOSED     *     * ALSO, note that the the purpose of handshaking (renegotiation is     * included) is to assign a different, and perhaps new, session to     * the connection.  The SSLv3 spec is a bit confusing on that new     * protocol feature.     */    private static final int    cs_START = 0;    private static final int    cs_HANDSHAKE = 1;    private static final int    cs_DATA = 2;    private static final int    cs_RENEGOTIATE = 3;    private static final int    cs_ERROR = 4;    private static final int   cs_SENT_CLOSE = 5;    private static final int    cs_CLOSED = 6;    private static final int    cs_APP_CLOSED = 7;      /*     * Client authentication be off, requested, or required.     *     * Migrated to SSLEngineImpl:     *    clauth_none/cl_auth_requested/clauth_required     */     /*     * Drives the protocol state machine.     */    private int                 connectionState;     /*     * Flag indicating if the next record we receive MUST be a Finished     * message. Temporarily set during the handshake to ensure that     * a change cipher spec message is followed by a finished message.     */    private boolean             expectingFinished;     /*     * For improved diagnostics, we detail connection closure     * If the socket is closed (connectionState >= cs_ERROR),     * closeReason != null indicates if the socket was closed     * because of an error or because or normal shutdown.     */    private SSLException        closeReason;     /*     * Per-connection private state that doesn't change when the     * session is changed.     */    private byte                doClientAuth;    private boolean             roleIsServer;    private boolean             enableSessionCreation = true;    private String              host;    private boolean             autoClose = true;    private AccessControlContext acc;     /*     * We cannot use the hostname resolved from name services.  For     * virtual hosting, multiple hostnames may be bound to the same IP     * address, so the hostname resolved from name services is not     * reliable.     */    private String              rawHostname;     // The cipher suites enabled for use on this connection.    private CipherSuiteList     enabledCipherSuites;     // The endpoint identification protocol    private String              identificationProtocol = null;     // The cryptographic algorithm constraints    private AlgorithmConstraints    algorithmConstraints = null;     /*     * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *     * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES.     * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME *     *     * There are several locks here.     *     * The primary lock is the per-instance lock used by     * synchronized(this) and the synchronized methods.  It controls all     * access to things such as the connection state and variables which     * affect handshaking.  If we are inside a synchronized method, we     * can access the state directly, otherwise, we must use the     * synchronized equivalents.     *     * The handshakeLock is used to ensure that only one thread performs     * the *complete initial* handshake.  If someone is handshaking, any     * stray application or startHandshake() requests who find the     * connection state is cs_HANDSHAKE will stall on handshakeLock     * until handshaking is done.  Once the handshake is done, we either     * succeeded or failed, but we can never go back to the cs_HANDSHAKE     * or cs_START state again.     *     * Note that the read/write() calls here in SSLSocketImpl are not     * obviously synchronized.  In fact, it's very nonintuitive, and     * requires careful examination of code paths.  Grab some coffee,     * and be careful with any code changes.     *     * There can be only three threads active at a time in the I/O     * subsection of this class.     *    1.  startHandshake     *    2.  AppInputStream     *    3.  AppOutputStream     * One thread could call startHandshake().     * AppInputStream/AppOutputStream read() and write() calls are each     * synchronized on 'this' in their respective classes, so only one     * app. thread will be doing a SSLSocketImpl.read() or .write()'s at     * a time.     *     * If handshaking is required (state cs_HANDSHAKE), and     * getConnectionState() for some/all threads returns cs_HANDSHAKE,     * only one can grab the handshakeLock, and the rest will stall     * either on getConnectionState(), or on the handshakeLock if they     * happen to successfully race through the getConnectionState().     *     * If a writer is doing the initial handshaking, it must create a     * temporary reader to read the responses from the other side.  As a     * side-effect, the writer's reader will have priority over any     * other reader.  However, the writer's reader is not allowed to     * consume any application data.  When handshakeLock is finally     * released, we either have a cs_DATA connection, or a     * cs_CLOSED/cs_ERROR socket.     *     * The writeLock is held while writing on a socket connection and     * also to protect the MAC and cipher for their direction.  The     * writeLock is package private for Handshaker which holds it while     * writing the ChangeCipherSpec message.     *     * To avoid the problem of a thread trying to change operational     * modes on a socket while handshaking is going on, we synchronize     * on 'this'.  If handshaking has not started yet, we tell the     * handshaker to change its mode.  If handshaking has started,     * we simply store that request until the next pending session     * is created, at which time the new handshaker's state is set.     *     * The readLock is held during readRecord(), which is responsible     * for reading an InputRecord, decrypting it, and processing it.     * The readLock ensures that these three steps are done atomically     * and that once started, no other thread can block on InputRecord.read.     * This is necessary so that processing of close_notify alerts     * from the peer are handled properly.     */    final private Object        handshakeLock = new Object();    final ReentrantLock         writeLock = new ReentrantLock();    final private Object        readLock = new Object();     private InputRecord         inrec;     /*     * Crypto state that's reinitialized when the session changes.     */    private MAC                 readMAC, writeMAC;    private CipherBox           readCipher, writeCipher;    // NOTE: compression state would be saved here     /*     * security parameters for secure renegotiation.     */    private boolean             secureRenegotiation;    private byte[]              clientVerifyData;    private byte[]              serverVerifyData;     /*     * The authentication context holds all information used to establish     * who this end of the connection is (certificate chains, private keys,     * etc) and who is trusted (e.g. as CAs or websites).     */    private SSLContextImpl      sslContext;      /*     * This connection is one of (potentially) many associated with     * any given session.  The output of the handshake protocol is a     * new session ... although all the protocol description talks     * about changing the cipher spec (and it does change), in fact     * that's incidental since it's done by changing everything that     * is associated with a session at the same time.  (TLS/IETF may     * change that to add client authentication w/o new key exchg.)     */    private Handshaker                  handshaker;    private SSLSessionImpl              sess;    private volatile SSLSessionImpl     handshakeSession;      /*     * If anyone wants to get notified about handshake completions,     * they'll show up on this list.     */    private HashMap<HandshakeCompletedListener, AccessControlContext>                                                        handshakeListeners;     /*     * Reuse the same internal input/output streams.     */    private InputStream         sockInput;    private OutputStream        sockOutput;      /*     * These input and output streams block their data in SSL records,     * and usually arrange integrity and privacy protection for those     * records.  The guts of the SSL protocol are wrapped up in these     * streams, and in the handshaking that establishes the details of     * that integrity and privacy protection.     */    private AppInputStream      input;    private AppOutputStream     output;     /*     * The protocol versions enabled for use on this connection.     *     * Note: we support a pseudo protocol called SSLv2Hello which when     * set will result in an SSL v2 Hello being sent with SSL (version 3.0)     * or TLS (version 3.1, 3.2, etc.) version info.     */    private ProtocolList enabledProtocols;     /*     * The SSL version associated with this connection.     */    private ProtocolVersion     protocolVersion = ProtocolVersion.DEFAULT;     /* Class and subclass dynamic debugging support */    private static final Debug debug = Debug.getInstance("ssl");     //    // CONSTRUCTORS AND INITIALIZATION CODE    //     /**     * Constructs an SSL connection to a named host at a specified port,     * using the authentication context provided.  This endpoint acts as     * the client, and may rejoin an existing SSL session if appropriate.     *     * @param context authentication context to use     * @param host name of the host with which to connect     * @param port number of the server's port     */    SSLSocketImpl(SSLContextImpl context, String host, int port)            throws IOException, UnknownHostException {        super();        this.host = host;        this.rawHostname = host;        init(context, false);        SocketAddress socketAddress =               host != null ? new InetSocketAddress(host, port) :               new InetSocketAddress(InetAddress.getByName(null), port);        connect(socketAddress, 0);    }      /**     * Constructs an SSL connection to a server at a specified address.     * and TCP port, using the authentication context provided.  This     * endpoint acts as the client, and may rejoin an existing SSL session     * if appropriate.     *     * @param context authentication context to use     * @param address the server's host     * @param port its port     */    SSLSocketImpl(SSLContextImpl context, InetAddress host, int port)            throws IOException {        super();        init(context, false);        SocketAddress socketAddress = new InetSocketAddress(host, port);        connect(socketAddress, 0);    }     /**     * Constructs an SSL connection to a named host at a specified port,     * using the authentication context provided.  This endpoint acts as     * the client, and may rejoin an existing SSL session if appropriate.     *     * @param context authentication context to use     * @param host name of the host with which to connect     * @param port number of the server's port     * @param localAddr the local address the socket is bound to     * @param localPort the local port the socket is bound to     */    SSLSocketImpl(SSLContextImpl context, String host, int port,            InetAddress localAddr, int localPort)            throws IOException, UnknownHostException {        super();        this.host = host;        this.rawHostname = host;        init(context, false);        bind(new InetSocketAddress(localAddr, localPort));        SocketAddress socketAddress =               host != null ? new InetSocketAddress(host, port) :               new InetSocketAddress(InetAddress.getByName(null), port);        connect(socketAddress, 0);    }      /**     * Constructs an SSL connection to a server at a specified address.     * and TCP port, using the authentication context provided.  This     * endpoint acts as the client, and may rejoin an existing SSL session     * if appropriate.     *     * @param context authentication context to use     * @param address the server's host     * @param port its port     * @param localAddr the local address the socket is bound to     * @param localPort the local port the socket is bound to     */    SSLSocketImpl(SSLContextImpl context, InetAddress host, int port,            InetAddress localAddr, int localPort)            throws IOException {        super();        init(context, false);        bind(new InetSocketAddress(localAddr, localPort));        SocketAddress socketAddress = new InetSocketAddress(host, port);        connect(socketAddress, 0);    }     /*     * Package-private constructor used ONLY by SSLServerSocket.  The     * java.net package accepts the TCP connection after this call is     * made.  This just initializes handshake state to use "server mode",     * giving control over the use of SSL client authentication.     */    SSLSocketImpl(SSLContextImpl context, boolean serverMode,            CipherSuiteList suites, byte clientAuth,            boolean sessionCreation, ProtocolList protocols,            String identificationProtocol,            AlgorithmConstraints algorithmConstraints) throws IOException {         super();        doClientAuth = clientAuth;        enableSessionCreation = sessionCreation;        this.identificationProtocol = identificationProtocol;        this.algorithmConstraints = algorithmConstraints;        init(context, serverMode);         /*         * Override what was picked out for us.         */        enabledCipherSuites = suites;        enabledProtocols = protocols;    }      /**     * Package-private constructor used to instantiate an unconnected     * socket. The java.net package will connect it, either when the     * connect() call is made by the application.  This instance is     * meant to set handshake state to use "client mode".     */    SSLSocketImpl(SSLContextImpl context) {        super();

Lines 1–500 of 2493.