java.lang.Objectjavax.net.ssl.SSLEngine
public abstract class SSLEngine
A class which enables secure communications using protocols such as the Secure Sockets Layer (SSL) or IETF RFC 2246 "Transport Layer Security" (TLS) protocols, but is transport independent.
The secure communications modes include:
The cipher suite used is established by a negotiation process called "handshaking". The goal of this process is to create or rejoin a "session", which may protect many connections over time. After handshaking has completed, you can access session attributes by using the getSession() method.
The SSLSocket class provides much of the same security functionality, but all of the inbound and outbound data is automatically transported using the underlying Socket , which by design uses a blocking model. While this is appropriate for many applications, this model does not provide the scalability required by large servers.
The primary distinction of an SSLEngine is that it operates on inbound and outbound byte streams, independent of the transport mechanism. It is the responsibility of the SSLEngine user to arrange for reliable I/O transport to the peer. By separating the SSL/TLS abstraction from the I/O transport mechanism, the SSLEngine can be used for a wide variety of I/O types, such as non-blocking I/O (polling) , selectable non-blocking I/O , Socket and the traditional Input/OutputStreams, local ByteBuffers or byte arrays, future asynchronous I/O models , and so on.
At a high level, the SSLEngine appears thus:
app data | ^ | | | v | | +----+-----|-----+----+ | | | | SSL|Engine | wrap() | | | unwrap() | OUTBOUND | INBOUND | | | | +----+-----|-----+----+ | | ^ | | | v | net dataApplication data (also known as plaintext or cleartext) is data which is produced or consumed by an application. Its counterpart is network data, which consists of either handshaking and/or ciphertext (encrypted) data, and destined to be transported via an I/O mechanism. Inbound data is data which has been received from the peer, and outbound data is destined for the peer.
(In the context of an SSLEngine, the term "handshake data" is taken to mean any data exchanged to establish and control a secure connection. Handshake data includes the SSL/TLS messages "alert", "change_cipher_spec," and "handshake.")
There are five distinct phases to an SSLEngine.
Data moves through the engine by calling wrap() or unwrap() on outbound or inbound data, respectively. Depending on the state of the SSLEngine, a wrap() call may consume application data from the source buffer and may produce network data in the destination buffer. The outbound data may contain application and/or handshake data. A call to unwrap() will examine the source buffer and may advance the handshake if the data is handshaking information, or may place application data in the destination buffer if the data is application. The state of the underlying SSL/TLS algorithm will determine when data is consumed and produced.
Calls to wrap() and unwrap() return an SSLEngineResult which indicates the status of the operation, and (optionally) how to interact with the engine to make progress.
The SSLEngine produces/consumes complete SSL/TLS packets only, and does not store application data internally between calls to wrap()/unwrap(). Thus input and output ByteBuffers must be sized appropriately to hold the maximum record that can be produced. Calls to SSLSession.getPacketBufferSize() and SSLSession.getApplicationBufferSize() should be used to determine the appropriate buffer sizes. The size of the outbound application data buffer generally does not matter. If buffer conditions do not allow for the proper consumption/production of data, the application must determine (via SSLEngineResult ) and correct the problem, and then try the call again.
Unlike SSLSocket, all methods of SSLEngine are non-blocking. SSLEngine implementations may require the results of tasks that may take an extended period of time to complete, or may even block. For example, a TrustManager may need to connect to a remote certificate validation service, or a KeyManager might need to prompt a user to determine which certificate to use as part of client authentication. Additionally, creating cryptographic signatures and verifying them can be slow, seemingly blocking.
For any operation which may potentially block, the SSLEngine will create a Runnable delegated task. When SSLEngineResult indicates that a delegated task result is needed, the application must call getDelegatedTask() to obtain an outstanding delegated task and call its run() method (possibly using a different thread depending on the compute strategy). The application should continue obtaining delegated tasks until no more exist, and try the original operation again.
At the end of a communication session, applications should properly close the SSL/TLS link. The SSL/TLS protocols have closure handshake messages, and these messages should be communicated to the peer before releasing the SSLEngine and closing the underlying transport mechanism. A close can be initiated by one of: an SSLException, an inbound closure handshake message, or one of the close methods. In all cases, closure handshake messages are generated by the engine, and wrap() should be repeatedly called until the resulting SSLEngineResult's status returns "CLOSED", or isOutboundDone() returns true. All data obtained from the wrap() method should be sent to the peer.
closeOutbound() is used to signal the engine that the application will not be sending any more data.
A peer will signal its intent to close by sending its own closure handshake message. After this message has been received and processed by the local SSLEngine's unwrap() call, the application can detect the close by calling unwrap() and looking for a SSLEngineResult with status "CLOSED", or if isInboundDone() returns true. If for some reason the peer closes the communication link without sending the proper SSL/TLS closure message, the application can detect the end-of-stream and can signal the engine via closeInbound() that there will no more inbound messages to process. Some applications might choose to require orderly shutdown messages from a peer, in which case they can check that the closure was generated by a handshake message and not by an end-of-stream condition.
There are two groups of cipher suites which you will need to know about when managing cipher suites:
Each SSL/TLS connection must have one client and one server, thus each endpoint must decide which role to assume. This choice determines who begins the handshaking process as well as which type of messages should be sent by each party. The method setUseClientMode(boolean) configures the mode. Once the initial handshaking has started, an SSLEngine can not switch between client and server modes, even when performing renegotiations.
Applications might choose to process delegated tasks in different threads. When an SSLEngine is created, the current AccessControlContext is saved. All future delegated tasks will be processed using this context: that is, all access control decisions will be made using the context captured at engine creation.
For example:
synchronized (outboundLock) { sslEngine.wrap(src, dst); outboundQueue.put(dst); }As a corollary, two threads must not attempt to call the same method (either wrap() or unwrap()) concurrently, because there is no way to guarantee the eventual packet ordering.
Constructor Summary | |
---|---|
protected |
SSLEngine
() Constructor for an SSLEngine providing no hints for an internal session reuse strategy. |
protected |
SSLEngine
(
String
peerHost, int peerPort) Constructor for an SSLEngine. |
Method Summary | |
---|---|
abstract void |
beginHandshake
() Initiates handshaking (initial or renegotiation) on this SSLEngine. |
abstract void |
closeInbound
() Signals that no more inbound network data will be sent to this SSLEngine. |
abstract void |
closeOutbound
() Signals that no more outbound application data will be sent on this SSLEngine. |
abstract Runnable |
getDelegatedTask
() Returns a delegated Runnable task for this SSLEngine. |
abstract String [] |
getEnabledCipherSuites
() Returns the names of the SSL cipher suites which are currently enabled for use on this engine. |
abstract String [] |
getEnabledProtocols
() Returns the names of the protocol versions which are currently enabled for use with this SSLEngine. |
abstract boolean |
getEnableSessionCreation
() Returns true if new SSL sessions may be established by this engine. |
abstract SSLEngineResult.HandshakeStatus |
getHandshakeStatus
() Returns the current handshake status for this SSLEngine. |
abstract boolean |
getNeedClientAuth
() Returns true if the engine will require client authentication. |
String |
getPeerHost
() Returns the host name of the peer. |
int |
getPeerPort
() Returns the port number of the peer. |
abstract SSLSession |
getSession
() Returns the SSLSession in use in this SSLEngine. |
![]() ![]() |
![]() ![]() ![]() |
abstract String [] |
getSupportedCipherSuites
() Returns the names of the cipher suites which could be enabled for use on this engine. |
abstract String [] |
getSupportedProtocols
() Returns the names of the protocols which could be enabled for use with this SSLEngine. |
abstract boolean |
getUseClientMode
() Returns true if the engine is set to use client mode when handshaking. |
abstract boolean |
getWantClientAuth
() Returns true if the engine will request client authentication. |
abstract boolean |
isInboundDone
() Returns whether unwrap(ByteBuffer, ByteBuffer) will accept any more inbound data messages. |
abstract boolean |
isOutboundDone
() Returns whether wrap(ByteBuffer, ByteBuffer) will produce any more outbound data messages. |
abstract void |
setEnabledCipherSuites
(
String
[] suites) Sets the cipher suites enabled for use on this engine. |
abstract void |
setEnabledProtocols
(
String
[] protocols) Set the protocol versions enabled for use on this engine. |
abstract void |
setEnableSessionCreation
(boolean flag) Controls whether new SSL sessions may be established by this engine. |
abstract void |
setNeedClientAuth
(boolean need) Configures the engine to require client authentication. |
![]() |
![]() ![]() ![]() ![]() |
abstract void |
setUseClientMode
(boolean mode) Configures the engine to use client (or server) mode when handshaking. |
abstract void |
setWantClientAuth
(boolean want) Configures the engine to request client authentication. |
SSLEngineResult |
unwrap
(
ByteBuffer
src,
ByteBuffer
dst) Attempts to decode SSL/TLS network data into a plaintext application data buffer. |
SSLEngineResult |
unwrap
(
ByteBuffer
src,
ByteBuffer
[] dsts) Attempts to decode SSL/TLS network data into a sequence of plaintext application data buffers. |
abstract SSLEngineResult |
unwrap
(
ByteBuffer
src,
ByteBuffer
[] dsts, int offset, int length) Attempts to decode SSL/TLS network data into a subsequence of plaintext application data buffers. |
SSLEngineResult |
wrap
(
ByteBuffer
[] srcs,
ByteBuffer
dst) Attempts to encode plaintext bytes from a sequence of data buffers into SSL/TLS network data. |
abstract SSLEngineResult |
wrap
(
ByteBuffer
[] srcs, int offset, int length,
ByteBuffer
dst) Attempts to encode plaintext bytes from a subsequence of data buffers into SSL/TLS network data. |
SSLEngineResult |
wrap
(
ByteBuffer
src,
ByteBuffer
dst) Attempts to encode a buffer of plaintext application data into SSL/TLS network data. |
Methods inherited from class java.lang. Object |
---|
clone , equals , finalize , getClass , hashCode , notify , notifyAll , toString , wait , wait , wait |
Constructor Detail |
---|
protected SSLEngine()
protected SSLEngine(String peerHost, int peerPort)
SSLEngine implementations may use the peerHost and peerPort parameters as hints for their internal session reuse strategy.
Some cipher suites (such as Kerberos) require remote hostname information. Implementations of this class should use this constructor to use Kerberos.
The parameters are not authenticated by the SSLEngine.
Method Detail |
---|
public String getPeerHost()
Note that the value is not authenticated, and should not be relied upon.
public int getPeerPort()
Note that the value is not authenticated, and should not be relied upon.
public SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException
An invocation of this method behaves in exactly the same manner as the invocation:
engine.wrap(new ByteBuffer [] { src }, 0, 1, dst);
- Parameters:
- src - a ByteBuffer containing outbound application data
- dst - a ByteBuffer to hold outbound network data
- Returns:
- an SSLEngineResult describing the result of this operation.
- Throws:
- SSLException - A problem was encountered while processing the data that caused the SSLEngine to abort. See the class description for more information on engine closure.
- ReadOnlyBufferException - if the dst buffer is read-only.
- IllegalArgumentException - if either src or dst is null.
- IllegalStateException - if the client/server mode has not yet been set.
- See Also:
- wrap(ByteBuffer [], int, int, ByteBuffer)
public SSLEngineResult wrap(ByteBuffer[] srcs, ByteBuffer dst) throws SSLException
An invocation of this method behaves in exactly the same manner as the invocation:
engine.wrap(srcs, 0, srcs.length, dst);
- Parameters:
- srcs - an array of ByteBuffers containing the outbound application data
- dst - a ByteBuffer to hold outbound network data
- Returns:
- an SSLEngineResult describing the result of this operation.
- Throws:
- SSLException - A problem was encountered while processing the data that caused the SSLEngine to abort. See the class description for more information on engine closure.
- ReadOnlyBufferException - if the dst buffer is read-only.
- IllegalArgumentException - if either srcs or dst is null, or if any element in srcs is null.
- IllegalStateException - if the client/server mode has not yet been set.
- See Also:
- wrap(ByteBuffer [], int, int, ByteBuffer)
public abstract SSLEngineResult wrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst) throws SSLException
Depending on the state of the SSLEngine, this method may produce network data without consuming any application data (for example, it may generate handshake data.)
The application is responsible for reliably transporting the network data to the peer, and for ensuring that data created by multiple calls to wrap() is transported in the same order in which it was generated. The application must properly synchronize multiple calls to this method.
If this SSLEngine has not yet started its initial handshake, this method will automatically start the handshake.
This method will attempt to produce one SSL/TLS packet, and will consume as much source data as possible, but will never consume more than the sum of the bytes remaining in each buffer. Each ByteBuffer's position is updated to reflect the amount of data consumed or produced. The limits remain the same.
The underlying memory used by the srcs and dst ByteBuffers must not be the same.
See the class description for more information on engine closure.
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException
An invocation of this method behaves in exactly the same manner as the invocation:
engine.unwrap(src, new ByteBuffer [] { dst }, 0, 1);
- Parameters:
- src - a ByteBuffer containing inbound network data.
- dst - a ByteBuffer to hold inbound application data.
- Returns:
- an SSLEngineResult describing the result of this operation.
- Throws:
- SSLException - A problem was encountered while processing the data that caused the SSLEngine to abort. See the class description for more information on engine closure.
- ReadOnlyBufferException - if the dst buffer is read-only.
- IllegalArgumentException - if either src or dst is null.
- IllegalStateException - if the client/server mode has not yet been set.
- See Also:
- unwrap(ByteBuffer, ByteBuffer [], int, int)
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException
An invocation of this method behaves in exactly the same manner as the invocation:
engine.unwrap(src, dsts, 0, dsts.length);
- Parameters:
- src - a ByteBuffer containing inbound network data.
- dsts - an array of ByteBuffers to hold inbound application data.
- Returns:
- an SSLEngineResult describing the result of this operation.
- Throws:
- SSLException - A problem was encountered while processing the data that caused the SSLEngine to abort. See the class description for more information on engine closure.
- ReadOnlyBufferException - if any of the dst buffers are read-only.
- IllegalArgumentException - if either src or dsts is null, or if any element in dsts is null.
- IllegalStateException - if the client/server mode has not yet been set.
- See Also:
- unwrap(ByteBuffer, ByteBuffer [], int, int)
public abstract SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length) throws SSLException
Depending on the state of the SSLEngine, this method may consume network data without producing any application data (for example, it may consume handshake data.)
The application is responsible for reliably obtaining the network data from the peer, and for invoking unwrap() on the data in the order it was received. The application must properly synchronize multiple calls to this method.
If this SSLEngine has not yet started its initial handshake, this method will automatically start the handshake.
This method will attempt to consume one complete SSL/TLS network packet, but will never consume more than the sum of the bytes remaining in the buffers. Each ByteBuffer's position is updated to reflect the amount of data consumed or produced. The limits remain the same.
The underlying memory used by the src and dsts ByteBuffers must not be the same.
The inbound network buffer may be modified as a result of this call: therefore if the network data packet is required for some secondary purpose, the data should be duplicated before calling this method. Note: the network data will not be useful to a second SSLEngine, as each SSLEngine contains unique random state which influences the SSL/TLS messages.
See the class description for more information on engine closure.
public abstract Runnable getDelegatedTask()
SSLEngine operations may require the results of operations that block, or may take an extended period of time to complete. This method is used to obtain an outstanding Runnable operation (task). Each task must be assigned a thread (possibly the current) to perform the run operation. Once the run method returns, the Runnable object is no longer needed and may be discarded.
Delegated tasks run in the AccessControlContext in place when this object was created.
A call to this method will return each outstanding task exactly once.
Multiple delegated tasks can be run in parallel.
public abstract void closeInbound() throws SSLException
If the application initiated the closing process by calling closeOutbound() , under some circumstances it is not required that the initiator wait for the peer's corresponding close message. (See section 7.2.1 of the TLS specification ( RFC 2246 ) for more information on waiting for closure alerts.) In such cases, this method need not be called.
But if the application did not initiate the closure process, or if the circumstances above do not apply, this method should be called whenever the end of the SSL/TLS data stream is reached. This ensures closure of the inbound side, and checks that the peer followed the SSL/TLS close procedure properly, thus detecting possible truncation attacks.
This method is idempotent: if the inbound side has already been closed, this method does not do anything.
wrap() should be called to flush any remaining handshake data.
public abstract boolean isInboundDone()
public abstract void closeOutbound()
This method is idempotent: if the outbound side has already been closed, this method does not do anything.
wrap(ByteBuffer, ByteBuffer) should be called to flush any remaining handshake data.
public abstract boolean isOutboundDone()
Note that during the closure phase, a SSLEngine may generate handshake closure data that must be sent to the peer. wrap() must be called to generate this data. When this method returns true, no more outbound data will be created.
public abstract String[] getSupportedCipherSuites()
public abstract String[] getEnabledCipherSuites()
Even if a suite has been enabled, it might never be used. (For example, the peer does not support it, the requisite certificates/private keys for the suite are not available, or an anonymous suite is enabled but authentication is required.)
public abstract void setEnabledCipherSuites(String[] suites)
Each cipher suite in the suites parameter must have been listed by getSupportedCipherSuites(), or the method will fail. Following a successful call to this method, only suites listed in the suites parameter are enabled for use.
See getEnabledCipherSuites() for more information on why a specific cipher suite may never be used on a engine.
public abstract String[] getSupportedProtocols()
public abstract String[] getEnabledProtocols()
public abstract void setEnabledProtocols(String[] protocols)
The protocols must have been listed by getSupportedProtocols() as being supported. Following a successful call to this method, only protocols listed in the protocols parameter are enabled for use.
public abstract SSLSession getSession()
These can be long lived, and frequently correspond to an entire login session for some user. The session specifies a particular cipher suite which is being actively used by all connections in that session, as well as the identities of the session's client and server.
Unlike SSLSocket.getSession() this method does not block until handshaking is complete.
Until the initial handshake has completed, this method returns a session object which reports an invalid cipher suite of "SSL_NULL_WITH_NULL_NULL".
public abstract void beginHandshake() throws SSLException
This method is not needed for the initial handshake, as the wrap() and unwrap() methods will implicitly call this method if handshaking has not already begun.
Note that the peer may also request a session renegotiation with this SSLEngine by sending the appropriate session renegotiate handshake message.
Unlike the SSLSocket#startHandshake() method, this method does not block until handshaking is completed.
To force a complete SSL/TLS session renegotiation, the current session should be invalidated prior to calling this method.
Some protocols may not support multiple handshakes on an existing engine and may throw an SSLException.
public abstract SSLEngineResult.HandshakeStatus getHandshakeStatus()
public abstract void setUseClientMode(boolean mode)
This method must be called before any handshaking occurs. Once handshaking has begun, the mode can not be reset for the life of this engine.
Servers normally authenticate themselves, and clients are not required to do so.
public abstract boolean getUseClientMode()
public abstract void setNeedClientAuth(boolean need)
An engine's client authentication setting is one of the following:
Unlike setWantClientAuth(boolean) , if this option is set and the client chooses not to provide authentication information about itself, the negotiations will stop and the engine will begin its closure procedure .
Calling this method overrides any previous setting made by this method or setWantClientAuth(boolean) .
public abstract boolean getNeedClientAuth()
public abstract void setWantClientAuth(boolean want)
An engine's client authentication setting is one of the following:
Unlike setNeedClientAuth(boolean) , if this option is set and the client chooses not to provide authentication information about itself, the negotiations will continue .
Calling this method overrides any previous setting made by this method or setNeedClientAuth(boolean) .
public abstract boolean getWantClientAuth()
public abstract void setEnableSessionCreation(boolean flag)
public abstract boolean getEnableSessionCreation()
public
SSLParameters
getSSLParameters
()
public void
setSSLParameters
(
SSLParameters
params)