/* * Copyright (c) 2003, 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.nio.*;import java.nio.ReadOnlyBufferException;import java.util.LinkedList;import java.security.*; import javax.crypto.BadPaddingException; import javax.net.ssl.*;import javax.net.ssl.SSLEngineResult.*; import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; /** * Implementation of an non-blocking SSLEngine. * * *Currently*, the SSLEngine code exists in parallel with the current * SSLSocket. As such, the current implementation is using legacy code * with many of the same abstractions. However, it varies in many * areas, most dramatically in the IO handling. * * There are three main I/O threads that can be existing in parallel: * wrap(), unwrap(), and beginHandshake(). We are encouraging users to * not call multiple instances of wrap or unwrap, because the data could * appear to flow out of the SSLEngine in a non-sequential order. We * take all steps we can to at least make sure the ordering remains * consistent, but once the calls returns, anything can happen. For * example, thread1 and thread2 both call wrap, thread1 gets the first * packet, thread2 gets the second packet, but thread2 gets control back * before thread1, and sends the data. The receiving side would see an * out-of-order error. * * Handshaking is still done the same way as SSLSocket using the normal * InputStream/OutputStream abstactions. We create * ClientHandshakers/ServerHandshakers, which produce/consume the * handshaking data. The transfer of the data is largely handled by the * HandshakeInStream/HandshakeOutStreams. Lastly, the * InputRecord/OutputRecords still have the same functionality, except * that they are overridden with EngineInputRecord/EngineOutputRecord, * which provide SSLEngine-specific functionality. * * Some of the major differences are: * * EngineInputRecord/EngineOutputRecord/EngineWriter: * * In order to avoid writing whole new control flows for * handshaking, and to reuse most of the same code, we kept most * of the actual handshake code the same. As usual, reading * handshake data may trigger output of more handshake data, so * what we do is write this data to internal buffers, and wait for * wrap() to be called to give that data a ride. * * All data is routed through * EngineInputRecord/EngineOutputRecord. However, all handshake * data (ct_alert/ct_change_cipher_spec/ct_handshake) are passed * through to the the underlying InputRecord/OutputRecord, and * the data uses the internal buffers. * * Application data is handled slightly different, we copy the data * directly from the src to the dst buffers, and do all operations * on those buffers, saving the overhead of multiple copies. * * In the case of an inbound record, unwrap passes the inbound * ByteBuffer to the InputRecord. If the data is handshake data, * the data is read into the InputRecord's internal buffer. If * the data is application data, the data is decoded directly into * the dst buffer. * * In the case of an outbound record, when the write to the * "real" OutputStream's would normally take place, instead we * call back up to the EngineOutputRecord's version of * writeBuffer, at which time we capture the resulting output in a * ByteBuffer, and send that back to the EngineWriter for internal * storage. * * EngineWriter is responsible for "handling" all outbound * data, be it handshake or app data, and for returning the data * to wrap() in the proper order. * * ClientHandshaker/ServerHandshaker/Handshaker: * Methods which relied on SSLSocket now have work on either * SSLSockets or SSLEngines. * * @author Brad Wetmore */final public class SSLEngineImpl extends SSLEngine { // // Fields and global comments // /* * 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. * - CLOSED when one side closes down, used to start the shutdown * process. SSL connection objects are not reused. * * 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. * * +---->-------+------>--------->-------+ * | | | * <-----< ^ ^ <-----< | *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE | * v v v | * | | | | * +------------+---------------+ | * | | * v | * ERROR>------>----->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 int connectionState; 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_CLOSED = 6; /* * Once we're in state cs_CLOSED, we can continue to * wrap/unwrap until we finish sending/receiving the messages * for close_notify. EngineWriter handles outboundDone. */ private boolean inboundDone = false; EngineWriter writer; /* * 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; /* * Client authentication be off, requested, or required. * * This will be used by both this class and SSLSocket's variants. */ static final byte clauth_none = 0; static final byte clauth_requested = 1; static final byte clauth_required = 2; /* * 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; /* * If someone tries to closeInbound() (say at End-Of-Stream) * our engine having received a close_notify, we need to * notify the app that we may have a truncation attack underway. */ private boolean recvCN; /* * For improved diagnostics, we detail connection closure * If the engine is closed (connectionState >= cs_ERROR), * closeReason != null indicates if the engine 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 enableSessionCreation = true; EngineInputRecord inputRecord; EngineOutputRecord outputRecord; private AccessControlContext acc; // 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; // Have we been told whether we're client or server? private boolean serverModeSet = false; private boolean roleIsServer; /* * 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; /* * 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; /* * 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. * * Note that we must never acquire the <code>this</code> lock after * <code>writeLock</code> or run the risk of deadlock. * * Grab some coffee, and be careful with any code changes. */ private Object wrapLock; private Object unwrapLock; Object writeLock; /* * Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); // // Initialization/Constructors // /** * Constructor for an SSLEngine from SSLContext, without * host/port hints. This Engine will not be able to cache * sessions, but must renegotiate everything by hand. */ SSLEngineImpl(SSLContextImpl ctx) { super(); init(ctx); } /** * Constructor for an SSLEngine from SSLContext. */ SSLEngineImpl(SSLContextImpl ctx, String host, int port) { super(host, port); init(ctx); } /** * Initializes the Engine */ private void init(SSLContextImpl ctx) { if (debug != null && Debug.isOn("ssl")) { System.out.println("Using SSLEngineImpl."); } sslContext = ctx; sess = SSLSessionImpl.nullSession; handshakeSession = null; /* * State is cs_START until we initialize the handshaker. * * Apps using SSLEngine are probably going to be server. * Somewhat arbitrary choice. */ roleIsServer = true; connectionState = cs_START; /* * default read and write side cipher and MAC support * * Note: compression support would go here too */ readCipher = CipherBox.NULL; readMAC = MAC.NULL; writeCipher = CipherBox.NULL; writeMAC = MAC.NULL; // default security parameters for secure renegotiation secureRenegotiation = false; clientVerifyData = new byte[0]; serverVerifyData = new byte[0]; enabledCipherSuites = sslContext.getDefaultCipherSuiteList(roleIsServer); enabledProtocols = sslContext.getDefaultProtocolList(roleIsServer); wrapLock = new Object(); unwrapLock = new Object(); writeLock = new Object(); /* * Save the Access Control Context. This will be used later * for a couple of things, including providing a context to * run tasks in, and for determining which credentials * to use for Subject based (JAAS) decisions */ acc = AccessController.getContext(); /* * All outbound application data goes through this OutputRecord, * other data goes through their respective records created * elsewhere. All inbound data goes through this one * input record. */ outputRecord = new EngineOutputRecord(Record.ct_application_data, this); inputRecord = new EngineInputRecord(this); inputRecord.enableFormatChecks(); writer = new EngineWriter(); } /** * Initialize the handshaker object. This means: * * . if a handshake is already in progress (state is cs_HANDSHAKE * or cs_RENEGOTIATE), do nothing and return * * . if the engine is already closed, throw an Exception (internal error) * * . otherwise (cs_START or cs_DATA), create the appropriate handshaker * object and advance the connection state (to cs_HANDSHAKE or * cs_RENEGOTIATE, respectively). * * This method is called right after a new engine is created, when * starting renegotiation, or when changing client/server mode of the * engine. */ private void initHandshaker() { switch (connectionState) { // // Starting a new handshake. // case cs_START: case cs_DATA: break; // // We're already in the middle of a handshake. // case cs_HANDSHAKE: case cs_RENEGOTIATE: return; // // Anyone allowed to call this routine is required to // do so ONLY if the connection state is reasonable... // default: throw new IllegalStateException("Internal error"); } // state is either cs_START or cs_DATA if (connectionState == cs_START) { connectionState = cs_HANDSHAKE; } else { // cs_DATA connectionState = cs_RENEGOTIATE; } if (roleIsServer) { handshaker = new ServerHandshaker(this, sslContext, enabledProtocols, doClientAuth, protocolVersion, connectionState == cs_HANDSHAKE, secureRenegotiation, clientVerifyData, serverVerifyData); } else { handshaker = new ClientHandshaker(this, sslContext, enabledProtocols, protocolVersion, connectionState == cs_HANDSHAKE, secureRenegotiation, clientVerifyData, serverVerifyData); } handshaker.setEnabledCipherSuites(enabledCipherSuites); handshaker.setEnableSessionCreation(enableSessionCreation); } /* * Report the current status of the Handshaker */ private HandshakeStatus getHSStatus(HandshakeStatus hss) { if (hss != null) { return hss; } synchronized (this) { if (writer.hasOutboundData()) { return HandshakeStatus.NEED_WRAP; } else if (handshaker != null) { if (handshaker.taskOutstanding()) { return HandshakeStatus.NEED_TASK; } else { return HandshakeStatus.NEED_UNWRAP; } } else if (connectionState == cs_CLOSED) { /* * Special case where we're closing, but * still need the close_notify before we * can officially be closed. * * Note isOutboundDone is taken care of by * hasOutboundData() above. */ if (!isInboundDone()) { return HandshakeStatus.NEED_UNWRAP; } // else not handshaking }Lines 1–500 of 2073. Load more
/* * Copyright (c) 2003, 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.nio.*; import java.nio.ReadOnlyBufferException; import java.util.LinkedList; import java.security.*; import javax.crypto.BadPaddingException; import javax.net.ssl.*; import javax.net.ssl.SSLEngineResult.*; import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager; /** * Implementation of an non-blocking SSLEngine. * * *Currently*, the SSLEngine code exists in parallel with the current * SSLSocket. As such, the current implementation is using legacy code * with many of the same abstractions. However, it varies in many * areas, most dramatically in the IO handling. * * There are three main I/O threads that can be existing in parallel: * wrap(), unwrap(), and beginHandshake(). We are encouraging users to * not call multiple instances of wrap or unwrap, because the data could * appear to flow out of the SSLEngine in a non-sequential order. We * take all steps we can to at least make sure the ordering remains * consistent, but once the calls returns, anything can happen. For * example, thread1 and thread2 both call wrap, thread1 gets the first * packet, thread2 gets the second packet, but thread2 gets control back * before thread1, and sends the data. The receiving side would see an * out-of-order error. * * Handshaking is still done the same way as SSLSocket using the normal * InputStream/OutputStream abstactions. We create * ClientHandshakers/ServerHandshakers, which produce/consume the * handshaking data. The transfer of the data is largely handled by the * HandshakeInStream/HandshakeOutStreams. Lastly, the * InputRecord/OutputRecords still have the same functionality, except * that they are overridden with EngineInputRecord/EngineOutputRecord, * which provide SSLEngine-specific functionality. * * Some of the major differences are: * * EngineInputRecord/EngineOutputRecord/EngineWriter: * * In order to avoid writing whole new control flows for * handshaking, and to reuse most of the same code, we kept most * of the actual handshake code the same. As usual, reading * handshake data may trigger output of more handshake data, so * what we do is write this data to internal buffers, and wait for * wrap() to be called to give that data a ride. * * All data is routed through * EngineInputRecord/EngineOutputRecord. However, all handshake * data (ct_alert/ct_change_cipher_spec/ct_handshake) are passed * through to the the underlying InputRecord/OutputRecord, and * the data uses the internal buffers. * * Application data is handled slightly different, we copy the data * directly from the src to the dst buffers, and do all operations * on those buffers, saving the overhead of multiple copies. * * In the case of an inbound record, unwrap passes the inbound * ByteBuffer to the InputRecord. If the data is handshake data, * the data is read into the InputRecord's internal buffer. If * the data is application data, the data is decoded directly into * the dst buffer. * * In the case of an outbound record, when the write to the * "real" OutputStream's would normally take place, instead we * call back up to the EngineOutputRecord's version of * writeBuffer, at which time we capture the resulting output in a * ByteBuffer, and send that back to the EngineWriter for internal * storage. * * EngineWriter is responsible for "handling" all outbound * data, be it handshake or app data, and for returning the data * to wrap() in the proper order. * * ClientHandshaker/ServerHandshaker/Handshaker: * Methods which relied on SSLSocket now have work on either * SSLSockets or SSLEngines. * * @author Brad Wetmore */ final public class SSLEngineImpl extends SSLEngine { // // Fields and global comments // /* * 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. * - CLOSED when one side closes down, used to start the shutdown * process. SSL connection objects are not reused. * * 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. * * +---->-------+------>--------->-------+ * | | | * <-----< ^ ^ <-----< | *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE | * v v v | * | | | | * +------------+---------------+ | * | | * v | * ERROR>------>----->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 int connectionState; 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_CLOSED = 6; /* * Once we're in state cs_CLOSED, we can continue to * wrap/unwrap until we finish sending/receiving the messages * for close_notify. EngineWriter handles outboundDone. */ private boolean inboundDone = false; EngineWriter writer; /* * 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; /* * Client authentication be off, requested, or required. * * This will be used by both this class and SSLSocket's variants. */ static final byte clauth_none = 0; static final byte clauth_requested = 1; static final byte clauth_required = 2; /* * 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; /* * If someone tries to closeInbound() (say at End-Of-Stream) * our engine having received a close_notify, we need to * notify the app that we may have a truncation attack underway. */ private boolean recvCN; /* * For improved diagnostics, we detail connection closure * If the engine is closed (connectionState >= cs_ERROR), * closeReason != null indicates if the engine 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 enableSessionCreation = true; EngineInputRecord inputRecord; EngineOutputRecord outputRecord; private AccessControlContext acc; // 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; // Have we been told whether we're client or server? private boolean serverModeSet = false; private boolean roleIsServer; /* * 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; /* * 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; /* * 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. * * Note that we must never acquire the <code>this</code> lock after * <code>writeLock</code> or run the risk of deadlock. * * Grab some coffee, and be careful with any code changes. */ private Object wrapLock; private Object unwrapLock; Object writeLock; /* * Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); // // Initialization/Constructors // /** * Constructor for an SSLEngine from SSLContext, without * host/port hints. This Engine will not be able to cache * sessions, but must renegotiate everything by hand. */ SSLEngineImpl(SSLContextImpl ctx) { super(); init(ctx); } /** * Constructor for an SSLEngine from SSLContext. */ SSLEngineImpl(SSLContextImpl ctx, String host, int port) { super(host, port); init(ctx); } /** * Initializes the Engine */ private void init(SSLContextImpl ctx) { if (debug != null && Debug.isOn("ssl")) { System.out.println("Using SSLEngineImpl."); } sslContext = ctx; sess = SSLSessionImpl.nullSession; handshakeSession = null; /* * State is cs_START until we initialize the handshaker. * * Apps using SSLEngine are probably going to be server. * Somewhat arbitrary choice. */ roleIsServer = true; connectionState = cs_START; /* * default read and write side cipher and MAC support * * Note: compression support would go here too */ readCipher = CipherBox.NULL; readMAC = MAC.NULL; writeCipher = CipherBox.NULL; writeMAC = MAC.NULL; // default security parameters for secure renegotiation secureRenegotiation = false; clientVerifyData = new byte[0]; serverVerifyData = new byte[0]; enabledCipherSuites = sslContext.getDefaultCipherSuiteList(roleIsServer); enabledProtocols = sslContext.getDefaultProtocolList(roleIsServer); wrapLock = new Object(); unwrapLock = new Object(); writeLock = new Object(); /* * Save the Access Control Context. This will be used later * for a couple of things, including providing a context to * run tasks in, and for determining which credentials * to use for Subject based (JAAS) decisions */ acc = AccessController.getContext(); /* * All outbound application data goes through this OutputRecord, * other data goes through their respective records created * elsewhere. All inbound data goes through this one * input record. */ outputRecord = new EngineOutputRecord(Record.ct_application_data, this); inputRecord = new EngineInputRecord(this); inputRecord.enableFormatChecks(); writer = new EngineWriter(); } /** * Initialize the handshaker object. This means: * * . if a handshake is already in progress (state is cs_HANDSHAKE * or cs_RENEGOTIATE), do nothing and return * * . if the engine is already closed, throw an Exception (internal error) * * . otherwise (cs_START or cs_DATA), create the appropriate handshaker * object and advance the connection state (to cs_HANDSHAKE or * cs_RENEGOTIATE, respectively). * * This method is called right after a new engine is created, when * starting renegotiation, or when changing client/server mode of the * engine. */ private void initHandshaker() { switch (connectionState) { // // Starting a new handshake. // case cs_START: case cs_DATA: break; // // We're already in the middle of a handshake. // case cs_HANDSHAKE: case cs_RENEGOTIATE: return; // // Anyone allowed to call this routine is required to // do so ONLY if the connection state is reasonable... // default: throw new IllegalStateException("Internal error"); } // state is either cs_START or cs_DATA if (connectionState == cs_START) { connectionState = cs_HANDSHAKE; } else { // cs_DATA connectionState = cs_RENEGOTIATE; } if (roleIsServer) { handshaker = new ServerHandshaker(this, sslContext, enabledProtocols, doClientAuth, protocolVersion, connectionState == cs_HANDSHAKE, secureRenegotiation, clientVerifyData, serverVerifyData); } else { handshaker = new ClientHandshaker(this, sslContext, enabledProtocols, protocolVersion, connectionState == cs_HANDSHAKE, secureRenegotiation, clientVerifyData, serverVerifyData); } handshaker.setEnabledCipherSuites(enabledCipherSuites); handshaker.setEnableSessionCreation(enableSessionCreation); } /* * Report the current status of the Handshaker */ private HandshakeStatus getHSStatus(HandshakeStatus hss) { if (hss != null) { return hss; } synchronized (this) { if (writer.hasOutboundData()) { return HandshakeStatus.NEED_WRAP; } else if (handshaker != null) { if (handshaker.taskOutstanding()) { return HandshakeStatus.NEED_TASK; } else { return HandshakeStatus.NEED_UNWRAP; } } else if (connectionState == cs_CLOSED) { /* * Special case where we're closing, but * still need the close_notify before we * can officially be closed. * * Note isOutboundDone is taken care of by * hasOutboundData() above. */ if (!isInboundDone()) { return HandshakeStatus.NEED_UNWRAP; } // else not handshaking }