所有类


javax.net.ssl
类 SSLEngine

java.lang.Object
  继承者 javax.net.ssl.SSLEngine

public abstract class SSLEngine
   
   
   
   
   
extends Object

此类允许使用安全套接字层 (SSL) 或 IETF RFC 2246 "Transport Layer Security" (TLS) 协议进行安全通信,但它与传输无关。

安全的通信模式包括:

  • 完整性保护。SSL/TLS 保护报文不被主动的窃听者修改。
  • 身份验证。在多数模式下,SSL/TLS 提供对等身份验证。服务器通常要进行身份验证,客户端也可在服务器的请求下进行身份验证。
  • 机密性(私有性保护)。在多数模式下,SSL/TLS 加密在客户端和服务器之间发送的数据。这保护了数据的机密性,所以被动的窃听者不能看到各种类型的敏感数据,如财务信息或个人信息。
这些类型的保护由一个“密码套件”指定,“密码套件”是由给定的 SSL 连接使用的加密算法组合。在协商过程中,两个端点必须对在双方的环境中都可用的密码套件达成一致。如果不存在这种公共的套件,就不能建立 SSL 连接,也不能交换数据。

通过称为“握手”的协商过程来建立所用的密码套件。此过程的目的是创建或重新加入一个“会话”,“会话”可以保护很多会话过程中的连接。握手结束后,可以使用 getSession() 方法访问会话的属性。

SSLSocket 类提供很多相同的安全功能,但是所有的入站和出站数据都是使用基础 Socket 自动地传输,基础 Socket 设计为使用阻塞模型。虽然这适合于很多应用程序,但是此模型却不提供大型服务器所需的可伸缩性。

SSLEngine 的主要特征是它在入站和出站的字节流上操作,与传输机制无关。安排到同位体可靠的 I/O 传输是 SSLEngine 用户的职责。通过从 I/O 传输机制中分离出 SSL/TLS 抽象,SSLEngine 可以被用于各种 I/O 类型,例如 non-blocking I/O (polling)selectable non-blocking I/OSocket 和传统的 Input/OutputStreams、本地的 ByteBuffers 或字节数组、未来的异步 I/O 模型等等。

从较高的层次上看,SSLEngine 表示为如下:

                   app data

                |           ^
                |     |     |
                v     |     |
           +----+-----|-----+----+
           |          |          |
           |       SSL|Engine    |
   wrap()  |          |          |  unwrap()
           | OUTBOUND | INBOUND  |
           |          |          |
           +----+-----|-----+----+
                |     |     ^
                |     |     |
                v           |

                   net data
 
应用程序数据(也称为纯文本或明文)是应用程序生成或使用的数据。它的对应物是网络数据,它由握手和/或密文(加密的)数据组成,并且注定要通过 I/O 机制传输。入站数据指的是从同位体接收的数据,出站数据是去往同位体的数据。

(在 SSLEngine 上下文中,术语“握手数据”的意思是所有用来建立和控制安全连接的已交换数据。握手数据包括 SSL/TLS 消息 "alert"、"change_cipher_spec" 和 "handshake。")

SSLEngine 有五种不同的阶段。

  1. 创建 - 已经创建和初始化 SSLEngine,但尚未被使用。在此阶段,应用程序可以设置任何特定于 SSLEngine 的设置(启用密码套件、SSLEngine 应该以客户端还是服务器模式握手等等)。一旦握手开始,任何新的设置(除了客户端/服务器模式,见下文)将在下一次握手时才被使用。
  2. 初始握手 - 初始握手是两个同位体交换通信参数,直到建立 SSLSession 为止的过程。在此阶段不能发送应用程序数据。
  3. 应用程序数据 - 一旦通信参数建立起来且握手完成,就可以通过 SSLEngine 传输应用程序数据。出站的应用程序报文被加密并进行完整性保护,入站的报文进行相反的过程。
  4. 重新握手 - 在应用程序数据阶段的任何时间,每一方都可以请求重新协商会话。新的握手数据可以混入到应用程序数据中。在开始重新握手阶段之前,应用程序可以重置 SSL/TLS 通信参数,例如已启用的密码套件列表和是否使用客户端身份验证,但是不能更改客户端/服务器模式。如前所述,一旦握手开始,任何新的 SSLEngine 配置设置都将在下一次握手时才被使用。
  5. 关闭 - 当不再需要连接时,应用程序应该关闭 SSLEngine,并且也应该在关闭基础传输机制之前发送/接收所有剩余的报文到同位体。一旦引擎关闭,它就是不可重用的:必须创建一个新的 SSLEngine
根据已初始化的 SSLContext 来调用 SSLContext.createSSLEngine() 即可创建 SSLEngine。在第一次调用 wrap()unwrap()beginHandshake() 之前应该设置所有的配置参数。这些方法都能触发初始握手。

分别对出站或入站数据调用 wrap()unwrap() 可使数据通过引擎。根据 SSLEngine 的状态,对 wrap() 的调用可能使用源缓冲区的应用程序数据,并且可能在目标缓冲区内生成网络数据。出站数据可以包含应用程序和/或握手数据。对 unwrap() 的调用将检查源缓冲区,如果数据是握手信息,则可能提前握手;如果数据是应用程序数据,则将其放入目标缓冲区中。基础 SSL/TLS 算法的状态将决定何时使用和生成数据。

调用 wrap()unwrap() 返回 SSLEngineResult,它指示操作的状态以及(可选的)如何与引擎交互以取得进展。

SSLEngine 只是生成/使用完整的 SSL/TLS 包,它不在 wrap()/unwrap() 的调用之间内部存储应用程序数据。因此输入和输出 ByteBuffer 必须设为合适的大小以便容纳可能生成的最多记录。要确定合适的缓冲区大小,应该调用 SSLSession.getPacketBufferSize()SSLSession.getApplicationBufferSize()。通常无需考虑出站应用程序数据缓冲区的大小。如果缓冲区的状况不允许正确地使用/生成数据,则应用程序必须加以确定(通过 SSLEngineResult)并纠正问题,然后再尝试调用一次。

SSLSocket 不同,SSLEngine 的所有方法都是非阻塞的。SSLEngine 实现所需的任务结果可能需要经过很长的时间才能获得,甚至可能被阻塞。例如,TrustManager 可能需要连接到远程的证书验证服务,或者 KeyManager 可能需要提示用户来确定将哪个证书用作客户端身份验证部分。另外,创建加密的签名和验证它们可能很慢,就好像阻塞一样。

对于任何可能阻塞的操作,SSLEngine 将创建 Runnable 委托任务。当 SSLEngineResult 指示需要一个委托任务结果时,应用程序必须调用 getDelegatedTask() 来获取一个未执行的委托任务并调用其 run() 方法(根据计算策略的不同,可能要使用不同的线程)。应用程序应该继续获取委托任务,直到没有为止,然后再尝试执行最初的操作。

在通信会话的结尾,应用程序应该正确地关闭 SSL/TLS 链接。SSL/TLS 协议有关闭握手报文,这些报文应该在释放 SSLEngine 并关闭基础传输机制之前传送到同位体。通过以下某个方法可发起关闭:SSLException、入站的关闭握手报文或某种 close 方法。在所有情况下,关闭握手报文由引擎生成,在 SSLEngineResult 的状态返回 "CLOSED",或者 isOutboundDone() 返回 true 之前应该重复调用 wrap()。从 wrap() 方法获得的所有数据都应该发送到同位体。

使用 closeOutbound() 通知引擎该应用程序将不再发送任何其他数据了。

同位体通过发送它自己的关闭握手报文来通知它的关闭意图。在此报文被本地 SSLEngineunwrap() 调用接收和处理后,应用程序可检测关闭,方法是调用 unwrap() 并寻找带有状态 "CLOSED" 的 SSLEngineResult,或者是 isInboundDone() 返回 true。如果由于某些原因使同位体关闭通信链接但没有发送正确的 SSL/TLS 关闭报文,则应用程序可以检测流的末尾并且能够通过 closeInbound() 来通知引擎没有更多的入站报文需要处理。某些应用程序可能选择要求同位体传送有序的关闭报文,在这种情况下,它们能够检查出关闭是由握手报文生成的,而不是由流的末尾这种情况引起的。

有两组密码套件是您在管理密码套件时需要知道的:

实现默认要求,默认只启用那些可对服务器进行身份验证并提供机密性的密码套件。只有双方明确同意可进行无需身份验证和/或非私有的(未加密的)通信时才选择这种密码套件。

每个 SSL/TLS 连接都必须有一个客户端和一个服务器,因此每一端必须决定担任哪种角色。这种选择决定了谁来开始握手过程以及每一方应该发送哪种类型的报文。方法 setUseClientMode(boolean) 可配置模式。一旦初始握手开始,SSLEngine 就不能在客户端和服务器模式间转换,甚至在执行重新协商时也不能。

应用程序可能选择在不同的线程中处理委托任务。当创建一个 SSLEngine 时,当前的 AccessControlContext 被保存。所有以后的委托任务都将使用此上下文来处理:也就是说,所有的访问控制决定都使用创建引擎时所捕获的上下文来做出。


并发性要点:下面是需要知道的两种并发性问题:
  1. wrap()unwrap() 方法可以互相并发执行。
  2. SSL/TLS 协议使用有序的包。应用程序必须小心保证生成的包按顺序传递。如果包无序到达,则可能出现不可预料的或灾难性的结果。

    例如:

                    synchronized (outboundLock) {
                        sslEngine.wrap(src, dst);
                        outboundQueue.put(dst);
                    }
            
    做为必然的结果,两个线程必须不能试图并发地调用相同的方法(wrap()unwrap()),因为没有方法保证最后包的排序。

从以下版本开始:
1.5
另请参见:
SSLContext, SSLSocket, SSLServerSocket, SSLSession, Socket

构造方法摘要
protected SSLEngine()
          SSLEngine 的构造方法,该构造方法不为内部会话重用策略提供提示。
protected SSLEngine(String peerHost, int peerPort)
          SSLEngine 的构造方法。
 
方法摘要
abstract  voidbeginHandshake()
          在此 SSLEngine 上发起握手(初始的或重新协商)。
abstract  voidcloseInbound()
          通知没有更多的入站网络数据将发送到此 SSLEngine
abstract  voidcloseOutbound()
          通知没有更多的出站应用程序数据将在此 SSLEngine 上发送。
abstract  RunnablegetDelegatedTask()
          返回此 SSLEngine 的一个委托 Runnable 任务。
abstract  String[]getEnabledCipherSuites()
          返回为了在此引擎上使用而当前已启用的 SSL 密码套件名称。
abstract  String[]getEnabledProtocols()
          返回当前已启用的,以便让 SSLEngine 使用的协议版本的名称。
abstract  booleangetEnableSessionCreation()
          如果可以由此引擎建立新的 SSL 会话,则返回 true。
abstract  SSLEngineResult.HandshakeStatusgetHandshakeStatus()
          返回此 SSLEngine 的当前握手状态。
abstract  booleangetNeedClientAuth()
          如果引擎要求 客户端身份验证,则返回 true。
 StringgetPeerHost()
          返回同位体的主机名。
 intgetPeerPort()
          返回同位体的端口号。
abstract  SSLSessiongetSession()
          返回此 SSLEngine 中使用的 SSLSession
abstract  String[]getSupportedCipherSuites()
          返回为了在此引擎上使用而可以启用的密码套件名称。
abstract  String[]getSupportedProtocols()
          返回能够被启用,以便让 SSLEngine 可使用的协议的名称。
abstract  booleangetUseClientMode()
          如果引擎设置为在握手时使用客户端模式,则返回 true。
abstract  booleangetWantClientAuth()
          如果引擎请求 客户端身份验证,则返回 true。
abstract  booleanisInboundDone()
          返回 unwrap(ByteBuffer, ByteBuffer) 是否再接受更多的入站数据报文。
abstract  booleanisOutboundDone()
          返回 wrap(ByteBuffer, ByteBuffer) 是否再生成更多的出站数据报文。
abstract  voidsetEnabledCipherSuites(String[] suites)
          设置密码套件为启用,以便在此引擎上使用。
abstract  voidsetEnabledProtocols(String[] protocols)
          设置为了在此引擎上使用而启用的协议版本。
abstract  voidsetEnableSessionCreation(boolean flag)
          控制是否可以由此引擎建立新的 SSL 会话。
abstract  voidsetNeedClientAuth(boolean need)
          配置引擎要求 客户端进行身份验证。
abstract  voidsetUseClientMode(boolean mode)
          配置引擎在握手时使用客户端(或服务器)模式。
abstract  voidsetWantClientAuth(boolean want)
          配置引擎请求 客户端身份验证。
 SSLEngineResultunwrap(ByteBuffer src, ByteBuffer dst)
          尝试把 SSL/TLS 网络数据解码到纯文本应用程序数据缓冲区中。
 SSLEngineResultunwrap(ByteBuffer src, ByteBuffer[] dsts)
          尝试把 SSL/TLS 网络数据解码到纯文本应用程序数据缓冲区序列中。
abstract  SSLEngineResultunwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length)
          尝试把 SSL/TLS 网络数据解码到纯文本应用程序数据缓冲区子序列中。
 SSLEngineResultwrap(ByteBuffer[] srcs, ByteBuffer dst)
          尝试把数据缓冲区序列中的纯文本字节编码成 SSL/TLS 网络数据。
abstract  SSLEngineResultwrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst)
          尝试把数据缓冲区字序列中的纯文本字节编码成 SSL/TLS 网络数据。
 SSLEngineResultwrap(ByteBuffer src, ByteBuffer dst)
          试图把缓冲区的纯文本应用程序数据编码成 SSL/TLS 网络数据。
 
从类 java.lang.Object 继承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

构造方法详细信息

SSLEngine

protected SSLEngine()
SSLEngine 的构造方法,该构造方法不为内部会话重用策略提供提示。

另请参见:
SSLContext.createSSLEngine(), SSLSessionContext

SSLEngine

protected SSLEngine(String peerHost,
                    int peerPort)
SSLEngine 的构造方法。

SSLEngine 实现可以使用 peerHostpeerPort 参数作为其内部会话重用策略的提示。

某些密码套件(例如 Kerberos)需要远程主机名信息。为了使用 Kerberos,此类的实现应该使用这种构造方法。

该参数不由 SSLEngine 进行身份验证。

参数:
peerHost - 同位体主机的名称
peerPort - 同位体的端口号
另请参见:
SSLContext.createSSLEngine(String, int), SSLSessionContext
方法详细信息

getPeerHost

public String getPeerHost()
返回同位体的主机名。

注意,该值未经身份验证,不应该依赖它。

返回:
同位体的主机名;如果没有可供使用的主机名,则返回 null。

getPeerPort

public int getPeerPort()
返回同位体的端口号。

注意,该值未经身份验证,不应该依赖它。

返回:
同位体的端口号;如果没有可供使用的端口号,则返回 -1。

wrap

public SSLEngineResult wrap(ByteBuffer src,
                            ByteBuffer dst)
                     throws SSLException
试图把缓冲区的纯文本应用程序数据编码成 SSL/TLS 网络数据。

调用此方法与调用下面的方法产生的行为完全相同:

 engine.wrap(new ByteBuffer [] { src }, 0, 1, dst);
 

参数:
src - 包含出站应用程序数据的 ByteBuffer
dst - 保存出站网络数据的 ByteBuffer
返回:
描述此次操作结果的 SSLEngineResult
抛出:
SSLException - 如果处理数据时遇到的问题导致 SSLEngine 中止。关于引擎关闭的更多信息,请参见该类的描述。
ReadOnlyBufferException - 如果 dst 缓冲区是只读的。
IllegalArgumentException - 如果 srcdst 为 null。
IllegalStateException - 如果没有设置客户端/服务器模式。
另请参见:
wrap(ByteBuffer [], int, int, ByteBuffer)

wrap

public SSLEngineResult wrap(ByteBuffer[] srcs,
                            ByteBuffer dst)
                     throws SSLException
尝试把数据缓冲区序列中的纯文本字节编码成 SSL/TLS 网络数据。

调用此方法与调用下面的方法产生的行为完全相同:

 engine.wrap(srcs, 0, srcs.length, dst);
 

参数:
srcs - 包含出站应用程序数据的 ByteBuffers 数组
dst - 保存出站网络数据的 ByteBuffer
返回:
描述此次操作结果的 SSLEngineResult
抛出:
SSLException - 如果处理数据时遇到的问题导致 SSLEngine 中止。关于引擎关闭的更多信息,请参见该类的描述。
ReadOnlyBufferException - 如果 dst 缓冲区是只读的。
IllegalArgumentException - 如果 srcsdst 为 null,或者 srcs 中的任何元素为 null。
IllegalStateException - 如果没有设置客户端/服务器模式。
另请参见:
wrap(ByteBuffer [], int, int, ByteBuffer)

wrap

public abstract SSLEngineResult wrap(ByteBuffer[] srcs,
                                     int offset,
                                     int length,
                                     ByteBuffer dst)
                              throws SSLException
尝试把数据缓冲区字序列中的纯文本字节编码成 SSL/TLS 网络数据。此“集中” 操作可在单个调用中对来自一个或多个给定缓冲区序列的字节序列进行编码。集中包装通常在实现网络协议或文件格式时很有用,例如将数据分组放入段中(这些段由一个或多个长度固定的头,后跟长度可变的正文组成)。关于集中的更多信息,请参见 GatheringByteChannel,有关子序列行为的更多信息,请参见 GatheringByteChannel.write(ByteBuffer[], int, int)

根据 SSLEngine 的状态,此方法可能生成网络数据而不使用任何应用程序数据(例如,它可能生成握手数据)。

应用程序负责把网络数据可靠地传输到同位体,同时也保证将多次调用 wrap() 所创建的数据以和它生成时相同的顺序传输。应用程序必须正确地同步对此方法的多次调用。

如果此 SSLEngine 还没有开始它的初始握手,则此方法将自动开始进行握手。

此方法将尝试生成一个 SSL/TLS 包,并使用尽可能多的源数据,但是使用的数据将从不会超过每个缓冲区中剩余字节的总和。会更新每个 ByteBuffer 的位置,以反映使用或生成的数据量。界限保持不变。

srcsdst ByteBuffer 使用的基础内存必须不能相同。

关于引擎关闭的更多信息,请参见该类的描述。

参数:
srcs - 包含出站应用程序数据的 ByteBuffers 数组
offset - 第一个缓冲区(要检索该缓冲区中的字节)在缓冲区数组中的偏移量;必须为非负数并且不能大于 srcs.length
length - 要访问的最大缓冲区编号;它必须为非负和不能大于 srcs.length - offset
dst - 保存出站网络数据的 ByteBuffer
返回:
描述此次操作结果的 SSLEngineResult
抛出:
SSLException - 如果处理数据时遇到的问题导致 SSLEngine 中止。关于引擎关闭的更多信息,请参见该类的描述。
IndexOutOfBoundsException - 如果关于 offsetlength 参数的前提不成立。
ReadOnlyBufferException - 如果 dst 缓冲区是只读的。
IllegalArgumentException - 如果 srcsdst 为 null, 或者指定的 srcs 子序列中的任何元素为 null。
IllegalStateException - 如果没有设置客户端/服务器模式。
另请参见:
GatheringByteChannel, GatheringByteChannel.write( ByteBuffer[], int, int)