SSLEngineImpl.java revision 2998
325N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 325N/A * This code is free software; you can redistribute it and/or modify it 325N/A * under the terms of the GNU General Public License version 2 only, as 325N/A * published by the Free Software Foundation. Oracle designates this 325N/A * particular file as subject to the "Classpath" exception as provided 325N/A * by Oracle in the LICENSE file that accompanied this code. 325N/A * This code is distributed in the hope that it will be useful, but WITHOUT 325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 325N/A * version 2 for more details (a copy is included in the LICENSE file that 325N/A * accompanied this code). 325N/A * You should have received a copy of the GNU General Public License version 325N/A * 2 along with this work; if not, write to the Free Software Foundation, 325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 325N/A * or visit www.oracle.com if you need additional information or have any 325N/A * Implementation of an non-blocking SSLEngine. 325N/A * *Currently*, the SSLEngine code exists in parallel with the current 325N/A * SSLSocket. As such, the current implementation is using legacy code 325N/A * with many of the same abstractions. However, it varies in many 325N/A * areas, most dramatically in the IO handling. 325N/A * There are three main I/O threads that can be existing in parallel: 325N/A * wrap(), unwrap(), and beginHandshake(). We are encouraging users to 325N/A * not call multiple instances of wrap or unwrap, because the data could 325N/A * appear to flow out of the SSLEngine in a non-sequential order. We 325N/A * take all steps we can to at least make sure the ordering remains 325N/A * consistent, but once the calls returns, anything can happen. For 325N/A * example, thread1 and thread2 both call wrap, thread1 gets the first 325N/A * packet, thread2 gets the second packet, but thread2 gets control back 325N/A * before thread1, and sends the data. The receiving side would see an 325N/A * Handshaking is still done the same way as SSLSocket using the normal 325N/A * handshaking data. The transfer of the data is largely handled by the * which provide SSLEngine-specific functionality. * Some of the major differences are: * 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 * 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 * 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 * 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. * Methods which relied on SSLSocket now have work on either * SSLSockets or SSLEngines. // 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 | * +------------+---------------+ | * 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 private static final int cs_DATA =
2;
* Once we're in state cs_CLOSED, we can continue to * for close_notify. EngineWriter handles outboundDone. * 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). * 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.) * Client authentication be off, requested, or required. * This will be used by both this class and SSLSocket's variants. * 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. * 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. * 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. * Per-connection private state that doesn't change when the // The cipher suites enabled for use on this connection. // hostname identification algorithm, the hostname identification is // Have we been told whether we're client or server? * 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. * The SSL version associated with this connection. * Crypto state that's reinitialized when the session changes. // NOTE: compression state would be saved here * security parameters for secure renegotiation. * 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. * Class and subclass dynamic debugging support * 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. * Constructor for an SSLEngine from SSLContext. * State is cs_START until we initialize the handshaker. * Apps using SSLEngine are probably going to be server. * Somewhat arbitrary choice. * default read and write side cipher and MAC support * Note: compression support would go here too // default security parameters for secure renegotiation * 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 * All outbound application data goes through this OutputRecord, * other data goes through their respective records created * elsewhere. All inbound data goes through this one * 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 // Starting a new handshake. // We're already in the middle of a handshake. // Anyone allowed to call this routine is required to // do so ONLY if the connection state is reasonable... // state is either cs_START or cs_DATA * Report the current status of the Handshaker * 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. }
// else not handshaking // Handshaking and connection state code * Provides "this" synchronization for connection state. * Otherwise, you can access it directly. * Get the Access Control Context. * Used for a known context to * run tasks in, and for determining which credentials * to use for Subject-based (JAAS) decisions. * Is a handshake currently underway? * When a connection finishes handshaking by enabling use of a newly * negotiated session, each end learns about it in two halves (read, * and write). When both read and write ciphers have changed, and the * last handshake message has been read, the connection has joined * (rejoined) the new session. * NOTE: The SSLv3 spec is rather unclear on the concepts here. * Sessions don't change once they're established (including cipher * suite and master secret) but connections can join them (and leave * them). They're created by handshaking, though sometime handshaking * causes connections to join up with pre-established sessions. * Synchronized on "this" from readRecord. "State error, change cipher specs");
// ... create decompressor * Dispose of any intermediate state in the underlying cipher. * For PKCS11 ciphers, this will release any attached sessions, * and thus make finalization faster. * Since MAC's doFinal() is called for every SSL/TLS packet, it's * not necessary to do the same with MAC's. * used by Handshaker to change the active write cipher, follows * the output of the CCS message. "State error, change cipher specs");
* Updates the SSL version associated with this connection. * Called from Handshaker once it has determined the negotiated version. * Kickstart the handshake if it is not already in progress. * . if handshaking is already underway, do nothing and return * . if the engine is not connected or already closed, throw an * . otherwise, call initHandshake() to initialize the handshaker * object and progress the state. Then, send the initial * handshaking message if appropriate (always on clients and * on servers when renegotiating). // handshaker already setup, proceed "Insecure renegotiation is not allowed");
"Warning: Using insecure renegotiation");
// initialize the handshaker, move to cs_RENEGOTIATE // handshaking already in progress, return // Kickstart handshake state machine if we need to ... // Note that handshaker.kickstart() writes the message // to its HandshakeOutStream, which calls back into // SSLSocketImpl.writeRecord() to send it. // prior to handshaking, activate the handshake // don't use SSLv2Hello when renegotiating }
else {
// instanceof ServerHandshaker // initial handshake, no kickstart message to send // we want to renegotiate, send hello request // hello request is not included in the handshake * Start a SSLEngine handshake "Couldn't kickstart handshaking", e);
* Unwraps a buffer. Does a variety of checks before grabbing * the unwrapLock, which blocks multiple unwraps from occuring. * Don't reset position so it looks like we didn't * consume anything. We did consume something, and it * got us into this situation, so report that much back. * Our days of consuming are now over anyway. "problem unwrapping net record", e);
return null;
// make compiler happy * Just in case something failed to reset limits properly. * Makes additional checks for unwrap, but this time more * specific to this packet and the current state of the machine. * See if the handshaker needs to report back some SSLException. * If we're still in cs_HANDSHAKE, make sure it's been * If there's still outbound data to flush, we * can return without trying to unwrap anything. * Grab a copy of this if it doesn't already exist, * and we can use it several places before anything major * happens on this side. Races aren't critical * If we have a task outstanding, this *MUST* be done before * doing any more unwrapping, because we could be in the middle * of receiving a handshake message, for example, a finished * message which would change the ciphers. * Check the packet to make sure enough is here. * This will also indirectly check for 0 len packets. // Is this packet bigger than SSL/TLS normally allows? "Input SSL/TLS record too big: max = " +
* To be considered: We could delay enforcing the application buffer * free space requirement until after the initial handshaking. * We're now ready to actually do the read. * The only result code we really need to be exactly * right is the HS finished, for signaling to * HandshakeCompletedListeners. * Check the various condition that we could be reporting. * It's *possible* something might have happened between the * above and now, but it was better to minimally lock "this" * during the read process. We'll return the current * status, which is more representative of the current state. * status above should cover: FINISHED, NEED_TASK * Actually do the read record processing. * Returns a Status if it can make specific determinations * of the engine state. In particular, we need to signal * that a handshake just completed. * It would be nice to be symmetrical with the write side and move * the majority of this to EngineInputRecord, but there's too much * SSLEngine state to do that cleanly. It must still live here. * The various operations will return new sliced BB's, * this will avoid having to worry about positions and * Read a record ... maybe emitting an alert if we get a * comprehensible but unsupported "hello" message during * format checking (e.g. V2). * The basic SSLv3 record protection involves (optional) * encryption for privacy, and an integrity check ensuring * data origin authentication. We do them both here, and * throw a fatal alert if the integrity check fails. // RFC 2246 states that decryption_failed should be used // for this purpose. However, that allows certain attacks, // so we just send bad record MAC. We also need to make // sure to always check the MAC to avoid a timing attack // for the same issue. See paper by Vaudenay et al. // rewind the BB if necessary. // use the same alert types as for MAC failure below "bad handshake record MAC");
// if (!inputRecord.decompress(c)) // fatal(Alerts.alert_decompression_failure, // "decompression failure"); * Handshake messages always go to a pending session * handshaker ... if there isn't one, create one. This * must work asynchronously, for renegotiation. * NOTE that handshaking will either resume a session * which was in the cache (and which might have other * connections in it already), or else will start a new * session (new keys exchanged) with just this connection // prior to handshaking, activate the handshake // don't use SSLv2Hello when renegotiating * process the handshake record ... may contain just * a partial handshake message or multiple messages. * The handshaker state machine will ensure that it's // if state is cs_RENEGOTIATE, revert it to cs_DATA // reset the parameters for secure renegotiation. // No handshakeListeners here. That's a // Pass this right back up to the application. "Data received in non-data state: " +
(
"Expecting finished message, received data");
* Don't return data once the inbound side is "illegal change cipher spec msg, state = " // The first message after a change_cipher_spec // record MUST be a "Finished" handshake record, // else it's a protocol violation. We force this // to be checked by a minor tweak to the state // next message MUST be a finished message // TLS requires that unrecognized records be ignored. ", Received record type: " * We only need to check the sequence number state for * non-handshaking record. * Note that in order to maintain the handshake status * properly, we check the sequence number after the last * record reading process. As we request renegotiation * or close the connection for wrapped sequence number * when there is enough sequence number space left to * handle a few more records, so the sequence number * of the last record cannot be wrapped. * Wraps a buffer. Does a variety of checks before grabbing * the wrapLock, which blocks multiple wraps from occuring. * We can be smarter about using smaller buffer sizes later. * For now, force it to be large enough to handle any "problem unwrapping net record", e);
return null;
// make compiler happy * Just in case something didn't reset limits properly. * Makes additional checks for unwrap, but this time more * specific to this packet and the current state of the machine. * See if the handshaker needs to report back some SSLException. * If we're still in cs_HANDSHAKE, make sure it's been * If there's no HS data available to write, we can return * without trying to wrap anything. * Grab a copy of this if it doesn't already exist, * and we can use it several places before anything major * happens on this side. Races aren't critical * If we have a task outstanding, this *MUST* be done before * doing any more wrapping, because we could be in the middle * of receiving a handshake message, for example, a finished * message which would change the ciphers. * This will obtain any waiting outbound data, or will * process the outbound appData. * writeRecord might have reported some status. * Now check for the remaining cases. * Central point to write/get all of the outgoing data. // eventually compress as well. * We only need to check the sequence number state for * non-handshaking record. * Note that in order to maintain the handshake status * properly, we check the sequence number after the last * record writing process. As we request renegotiation * or close the connection for wrapped sequence number * when there is enough sequence number space left to * handle a few more records, so the sequence number * of the last record cannot be wrapped. * Non-application OutputRecords go through here. // eventually compress as well. * Check the sequence number state * Note that in order to maintain the connection I/O * properly, we check the sequence number after the last * record writing process. As we request renegotiation * or close the connection for wrapped sequence number * when there is enough sequence number space left to * handle a few more records, so the sequence number * of the last record cannot be wrapped. * Check the sequence number state * RFC 4346 states that, "Sequence numbers are of type uint64 and * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS * implementation would need to wrap a sequence number, it must * Return true if the handshake status may be changed. * Don't bother to check the sequence number for error or * closed connections, or NULL MAC * Conservatively, close the connection immediately when the * sequence number is close to overflow * TLS protocols do not define a error alert for sequence * number overflow. We use handshake_failure error alert * for handshaking and bad_record_mac for other records. ", sequence number extremely close to overflow " +
"(2^64-1 packets). Closing connection.");
return true;
// make the compiler happy * Ask for renegotiation when need to renew sequence number. * Don't bother to kickstart the renegotiation when the local is "to avoid sequence number overflow");
* Signals that no more outbound application data will be sent * on this <code>SSLEngine</code>. * If we haven't even started yet, don't bother reading inbound. * Otherwise we indicate clean termination. // See comment in changeReadCiphers() * Dump out a close_notify to the remote side * Returns the outbound application data closure state * Signals that no more inbound network data will be sent * to this <code>SSLEngine</code>. // See comment in changeReadCiphers() * Close the inbound side of the connection. We grab the * lock here, and do the real work in the internal verison. * We do check for truncation attacks. * Currently closes the outbound side as well. The IETF TLS * working group has expressed the opinion that 1/2 open * connections are not allowed by the spec. May change * No need to throw an Exception if we haven't even started yet. recvCN =
true;
// Only receive the Exception once "Inbound closed before receiving peer's close_notify: " +
"possible truncation attack?");
* Currently, this is a no-op, but in case we change * the close inbound code later. * Returns the network inbound data closure state * Returns the current <code>SSLSession</code> for this * These can be long lived, and frequently correspond to an * entire login session for some user. * Returns a delegated <code>Runnable</code> task for * this <code>SSLEngine</code>. // EXCEPTION AND ALERT HANDLING * We've got a fatal error here, so start the shutdown process. * Because of the way the code was written, we have some code * calling fatal directly when the "description" is known * and some throwing Exceptions which are then caught by higher * levels which then call here. This code needs to determine * if one of the lower levels has already started the process. * We won't worry about Error's, if we have one of those, * we're in worse trouble. Note: the networking code doesn't * deal with Errors either. * If we have no further information, make a general-purpose * message for folks to see. We generally have one or the other. * If we've already shutdown because of an error, * there is nothing we can do except rethrow the exception. * Most exceptions seen here will be SSLExceptions. * We may find the occasional Exception which hasn't been * converted to a SSLException, so we'll do it here. ", fatal: engine already closed. Rethrowing " +
"fatal SSLEngine condition");
* Ok, this engine's going down. * If we haven't even started handshaking yet, no need * to generate the fatal close alert. * Including RuntimeExceptions, but we'll throw those * down below. The closeReason isn't used again, * except for null checks. // See comment in changeReadCiphers() * Process an incoming alert ... caller must already have synchronized "Received close_notify during handshake");
// The other legal warnings relate to certificates, // e.g. no_certificate, bad_certificate, etc; these // are important to the handshaking code, which can // also handle illegal protocol alerts if needed. }
else {
// fatal or unknown level * Emit alerts. Caller must have synchronized with "this". // the connectionState cannot be cs_START // For initial handshaking, don't send alert message to peer if // handshaker has not started. ", Exception sending alert: " + e);
// VARIOUS OTHER METHODS (COMMON TO SSLSocket) * Controls whether new connections may cause creation of new SSL * As long as handshaking has not started, we can change * whether we enable session creations. Otherwise, * we will need to wait for the next handshake. * Returns true if new connections may cause creation of new SSL * Sets the flag controlling whether a server mode engine * *REQUIRES* SSL client authentication. * As long as handshaking has not started, we can change * whether client authentication is needed. Otherwise, * we will need to wait for the next handshake. * Sets the flag controlling whether a server mode engine * *REQUESTS* SSL client authentication. * As long as handshaking has not started, we can change * whether client authentication is requested. Otherwise, * we will need to wait for the next handshake. * Sets the flag controlling whether the engine is in SSL * client or server mode. Must be called before any SSL * If we need to change the engine mode and the enabled * protocols haven't specifically been set by the user, * change them to the corresponding default ones. * If we have a handshaker, but haven't started * SSL traffic, we can throw away our current * handshaker, and start from scratch. Don't * need to call doneConnect() again, we already * If we need to change the engine mode and the enabled * protocols haven't specifically been set by the user, * change them to the corresponding default ones. // If handshake has started, that's an error. Fall through... ", setUseClientMode() invoked in state = " +
* We can let them continue if they catch this correctly, * we don't need to shut this down. "Cannot change mode after SSL traffic has started");
* Returns the names of the cipher suites which could be enabled for use * on an SSL connection. Normally, only a subset of these will actually * be enabled by default, since this list may include cipher suites which * do not support the mutual authentication of servers and clients, or * which do not protect data confidentiality. Servers may also need * certain kinds of certificates to use certain cipher suites. * @return an array of cipher suite names * Controls which particular cipher suites are enabled for use on * this connection. The cipher suites must have been listed by * getCipherSuites() as being supported. Even if a suite has been * enabled, it might never be used if no peer supports it or the * requisite certificates (and private keys) are not available. * @param suites Names of all the cipher suites to enable. * Returns the names of the SSL cipher suites which are currently enabled * for use on this connection. When an SSL engine is first created, * all enabled cipher suites <em>(a)</em> protect data confidentiality, * by traffic encryption, and <em>(b)</em> can mutually authenticate * both clients and servers. Thus, in some environments, this value * @return an array of cipher suite names * Returns the protocols that are supported by this implementation. * A subset of the supported protocols may be enabled for this connection * @ returns an array of protocol names. * Controls which protocols are enabled for use on * this connection. The protocols must have been listed by * getSupportedProtocols() as being supported. * @param protocols protocols to enable. * @exception IllegalArgumentException when one of the protocols * named by the parameter is not supported. * Try to configure the endpoint identification algorithm of the engine. * @param identificationAlgorithm the algorithm used to check the * @return true if the identification algorithm configuration success. * Returns the endpoint identification algorithm of the engine. * Return the name of the current thread. Utility method. * Returns a printable representation of this end of the connection.