添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

The script content on this page is for navigation purposes only and does not alter the content in any way.

The Java Secure Socket Extension (JSSE) enables secure Internet communications. It provides a framework and an implementation for a Java version of the TLS and DTLS protocols and includes functionality for data encryption, server authentication, message integrity, and optional client authentication.

Introduction to JSSE

Data that travels across a network can easily be accessed by someone who is not the intended recipient. When the data includes private information, such as passwords and credit card numbers, steps must be taken to make the data unintelligible to unauthorized parties. It is also important to ensure that the data has not been modified, either intentionally or unintentionally, during transport. The Transport Layer Security (TLS) protocol was designed to help protect the privacy and integrity of data while it is being transferred across a network.

The Java Secure Socket Extension (JSSE) enables secure Internet communications. It provides a framework and an implementation for a Java version of the TLS protocol and includes functionality for data encryption, server authentication, message integrity, and optional client authentication. Using JSSE, developers can provide for the secure passage of data between a client and a server running any application protocol (such as HTTP, Telnet, or FTP) over TCP/IP.

By abstracting the complex underlying security algorithms and handshaking mechanisms, JSSE minimizes the risk of creating subtle but dangerous security vulnerabilities. Furthermore, it simplifies application development by serving as a building block that developers can integrate directly into their applications.

JSSE provides both an application programming interface (API) framework and an implementation of that API. The JSSE API supplements the core network and cryptographic services defined by the java.security and java.net packages by providing extended networking socket classes, trust managers, key managers, SSL contexts, and a socket factory framework for encapsulating socket creation behavior. Because the SSLSocket class is based on a blocking I/O model, the Java Development Kit (JDK) includes a nonblocking SSLEngine class to enable implementations to choose their own I/O methods.

The JSSE API supports the following security protocols:

DTLS: versions 1.0 and 1.2

TLS: version 1.0, 1.1, 1.2, and 1.3

SSL (Secure Socket Layer): version 3.0

These security protocols encapsulate a normal bidirectional stream socket, and the JSSE API adds transparent support for authentication, encryption, and integrity protection.

JSSE is a security component of the Java SE platform, and is based on the same design principles found elsewhere in the Java Cryptography Architecture (JCA) Reference Guide framework. This framework for cryptography-related security components allows them to have implementation independence and, whenever possible, algorithm independence. JSSE uses the Cryptographic Service Providers defined by the JCA framework.

Other security components in the Java SE platform include the Java Authentication and Authorization Service (JAAS) Reference Guide and the Java Security Tools . JSSE encompasses many of the same concepts and algorithms as those in JCA but automatically applies them underneath a simple stream socket API.

The JSSE API was designed to allow other SSL/TLS/DTLS protocols and Public Key Infrastructure (PKI) implementations to be plugged in seamlessly. Developers can also provide alternative logic to determine if remote hosts should be trusted or what authentication key material should be sent to a remote host.

JSSE Features and Benefits

JSSE includes the following important benefits and features:

  • Included as a standard component of the JDK
  • Extensible, provider-based architecture
  • Implemented in 100% pure Java
  • Provides API support for TLS/DTLS
  • Provides implementations of SSL 3.0, TLS (versions 1.0, 1.1, 1.2, and 1.3), and DTLS (versions 1.0 and 1.2)
  • Includes classes that can be instantiated to create secure channels ( SSLSocket , SSLServerSocket , and SSLEngine )
  • Provides support for cipher suite negotiation, which is part of the TLS/DTLS handshaking used to initiate or verify secure communications
  • Provides support for client and server authentication, which is part of the normal TLS/DTLS handshaking
  • Provides support for HTTP encapsulated in the TLS protocol, which allows access to data such as web pages using HTTPS
  • Provides server session management APIs to manage memory-resident SSL sessions
  • Provides support for the certificate status request extension (OCSP stapling), which saves client certificate validation round-trips and resources
  • Provides support for the Server Name Indication (SNI) rxtension, which extends the TLS/DTLS protocols to indicate what server name the client is attempting to connect to during handshaking
  • Provides support for endpoint identification during handshaking, which prevents man-in-the-middle attacks
  • Provides support for cryptographic algorithm constraints, which provides fine-grained control over algorithms negotiated by JSSE
  • JSSE Standard API

    The JSSE standard API, available in the javax.net and javax.net.ssl packages, provides:

  • Secure sockets tailored to client and server-side applications.
  • A non-blocking engine for producing and consuming streams of TLS/DTLS data ( SSLEngine ).
  • Factories for creating sockets, server sockets, SSL sockets, and SSL server sockets. By using socket factories, you can encapsulate socket creation and configuration behavior.
  • A class representing a secure socket context that acts as a factory for secure socket factories and engines.
  • Key and trust manager interfaces (including X.509-specific key and trust managers), and factories that can be used for creating them.
  • A class for secure HTTP URL connections (HTTPS).
  • SunJSSE Provider

    Oracle's implementation of Java SE includes a JSSE provider named SunJSSE , which comes preinstalled and preregistered with the JCA. This provider supplies the following cryptographic services:

  • An implementation of the SSL 3.0, TLS (versions 1.0, 1.1, 1.2, and 1.3), and DTLS (versions 1.0 and 1.2) security protocols.
  • An implementation of the most common TLS and DTLS cipher suites. This implementation encompasses a combination of authentication, key agreement, encryption, and integrity protection.
  • An implementation of an X.509-based key manager that chooses appropriate authentication keys from a standard JCA keystore.
  • An implementation of an X.509-based trust manager that implements rules for certificate chain validation.
  • See The SunJSSE Provider .

    JSSE Related Documentation

    The following list contains links to online documentation and names of books about related subjects:

    JSSE API Documentation

    javax.net package

    javax.net.ssl package

    To communicate securely, both sides of the connection must be SSL-enabled. In the JSSE API, the endpoint classes of the connection are SSLSocket and SSLEngine . In Figure 8-1 , the major classes used to create SSLSocket and SSLEngine are laid out in a logical ordering.

    Figure 8-1 JSSE Classes Used to Create SSLSocket and SSLEngine

    Description of Figure 8-1 follows
    Description of "Figure 8-1 JSSE Classes Used to Create SSLSocket and SSLEngine"

    An SSLSocket is created either by an SSLSocketFactory or by an SSLServerSocket accepting an inbound connection. In turn, an SSLServerSocket is created by an SSLServerSocketFactory . Both SSLSocketFactory and SSLServerSocketFactory objects are created by an SSLContext . An SSLEngine is created directly by an SSLContext , and relies on the application to handle all I/O.

    Note:

    When using raw SSLSocket or SSLEngine classes, you should always check the peer's credentials before sending any data. Since JDK 7, endpoint identification/verification procedures can be handled during SSL/TLS handshaking. See the method SSLParameters.setEndpointIdentificationAlgorithm .

    For example, the host name in a URL should match the host name in the peer's credentials. An application could be exploited with URL spoofing if the host name is not verified.

    The abstract javax.net.SocketFactory class is used to create sockets. Subclasses of this class are factories that create particular subclasses of sockets and thus provide a general framework for the addition of public socket-level functionality. For example, see SSLSocketFactory and SSLServerSocketFactory Classes .

    The abstract javax.net.ServerSocketFactory class is analogous to the SocketFactory class, but is used specifically for creating server sockets.

    Socket factories are a simple way to capture a variety of policies related to the sockets being constructed, producing such sockets in a way that does not require special configuration of the code that asks for the sockets:

  • Due to polymorphism of both factories and sockets, different kinds of sockets can be used by the same application code just by passing different kinds of factories.
  • Factories can themselves be customized with parameters used in socket construction. For example, factories could be customized to return sockets with different networking timeouts or security parameters already configured.
  • The sockets returned to the application can be subclasses of java.net.Socket (or javax.net.ssl.SSLSocket ), so that they can directly expose new APIs for features such as compression, security, record marking, statistics collection, or firewall tunneling.

    The javax.net.ssl.SSLSocketFactory class acts as a factory for creating secure sockets. This class is an abstract subclass of javax.net.SocketFactory .

    Secure socket factories encapsulate the details of creating and initially configuring secure sockets. This includes authentication keys, peer certificate validation, enabled cipher suites, and the like.

    The javax.net.ssl.SSLServerSocketFactory class is analogous to the SSLSocketFactory class, but is used specifically for creating server sockets.

  • Get the default factory by calling the SSLSocketFactory.getDefault() static method.
  • Receive a factory as an API parameter. That is, code that must create sockets but does not care about the details of how the sockets are configured can include a method with an SSLSocketFactory parameter that can be called by clients to specify which SSLSocketFactory to use when creating sockets (for example, javax.net.ssl.HttpsURLConnection ).
  • Construct a new factory with specifically configured behavior.
  • The default factory is typically configured to support server authentication only so that sockets created by the default factory do not leak any more information about the client than a normal TCP socket would.

    Many classes that create and use sockets do not need to know the details of socket creation behavior. Creating sockets through a socket factory passed in as a parameter is a good way of isolating the details of socket configuration, and increases the reusability of classes that create and use sockets.

    You can create new socket factory instances either by implementing your own socket factory subclass or by using another class which acts as a factory for socket factories. One example of such a class is SSLContext , which is provided with the JSSE implementation as a provider-based configuration class.

    The javax.net.ssl.SSLSocket class is a subclass of the standard Java java.net.Socket class. It supports all of the standard socket methods and adds methods specific to secure sockets. Instances of this class encapsulate the SSLContext under which they were created. See SSLContext Class . There are APIs to control the creation of secure socket sessions for a socket instance, but trust and key management are not directly exposed.

    The javax.net.ssl.SSLServerSocket class is analogous to the SSLSocket class, but is used specifically for creating server sockets.

    To prevent peer spoofing, you should always verify the credentials presented to an SSLSocket . See Cipher Suite Choice and Remote Entity Verification .

    Note:

    Due to the complexity of the SSL and TLS protocols, it is difficult to predict whether incoming bytes on a connection are handshake or application data, and how that data might affect the current connection state (even causing the process to block). In the Oracle JSSE implementation, the available() method on the object obtained by SSLSocket.getInputStream() returns a count of the number of application data bytes successfully decrypted from the SSL connection but not yet read by the application.
    Obtaining an SSLSocket

    Instances of SSLSocket can be obtained in one of the following ways:

  • An SSLSocket can be created by an instance of SSLSocketFactory via one of the several createSocket methods of that class.
  • An SSLSocket can be created through the accept method of the SSLServerSocket class.
  • Cipher Suite Choice and Remote Entity Verification

    The SSL/TLS protocols define a specific series of steps to ensure a protected connection. However, the choice of cipher suite directly affects the type of security that the connection enjoys. For example, if an anonymous cipher suite is selected, then the application has no way to verify the remote peer's identity. If a suite with no encryption is selected, then the privacy of the data cannot be protected. Additionally, the SSL/TLS protocols do not specify that the credentials received must match those that peer might be expected to send. If the connection were somehow redirected to a rogue peer, but the rogue's credentials were acceptable based on the current trust material, then the connection would be considered valid.

    When using raw SSLSocket and SSLEngine classes, you should always check the peer's credentials before sending any data. The SSLSocket and SSLEngine classes do not automatically verify that the host name in a URL matches the host name in the peer's credentials. An application could be exploited with URL spoofing if the host name is not verified. Since JDK 7, endpoint identification/verification procedures can be handled during SSL/TLS handshaking. See the SSLParameters.getEndpointIdentificationAlgorithm method.

    Protocols such as HTTPS ( HTTP Over TLS ) do require host name verification. Since JDK 7, the HTTPS endpoint identification is enforced during handshaking for HttpsURLConnection by default. See the SSLParameters.getEndpointIdentificationAlgorithm method. Alternatively, applications can use the HostnameVerifier interface to override the default HTTPS host name rules. See HostnameVerifier Interface and HttpsURLConnection Class .

    SSLEngine Class

    As mentioned previously, TLS/DTLS are standard protocols for secure network communications, and are being used in a wide variety of applications across a wide range of computing platforms and devices. Along with this popularity come demands to use TLS/DTLS with different I/O and threading models to satisfy the applications' performance, scalability, footprint, and other requirements. There are demands to use TLS/DTLS with blocking and nonblocking I/O channels, asynchronous I/O, arbitrary input and output streams, and byte buffers. There are demands to use it in highly scalable, performance-critical environments, requiring management of thousands of network connections.

    Abstracting the I/O transport mechanism using the SSLEngine class in Java SE allows applications to use the TLS/DTLS protocols in a transport-independent way, and thus frees application developers to choose transport and computing models that best meet their needs. Not only does this abstraction allow applications to use nonblocking I/O channels and other I/O models, it also accommodates different threading models. This effectively leaves the I/O and threading decisions up to the application developer. Because of this flexibility, the application developer must manage I/O and threading (complex topics in and of themselves), as well as have some understanding of the TLS/DTLS protocols. Because the SSLEngine class requires an understanding of SSL/TLS, I/O, and threading models, it is considered an advanced API: beginners should use SSLSocket .

    Users of other Java programming language APIs such as the Java Generic Security Services (Java GSS-API) and the Java Simple Authentication Security Layer (Java SASL) will notice similarities in that the application is also responsible for transporting data.

    The core class is javax.net.ssl.SSLEngine . It encapsulates a TLS/DTLS state machine and operates on inbound and outbound byte buffers that are filled and drained respectively by the user of the SSLEngine class. Figure 8-2 illustrates the flow of data from the application, through SSLEngine , to the transport mechanism, and back.

    Figure 8-2 Flow of Data Through SSLEngine

    The following text describes this figure.

    Calls to SSLEngine produce and consume TLS/DTLS packets, which must then be exchanged with the peer. The nomenclature for SSLEngine data is always from the perspective of the local side: data bound for the peer is called outbound data , and the peer's data for the local side is called inbound data . Before application data can be produced/consumed from the application buffers, a handshaking procedure that negotiates security parameters must complete. The handshake data that is produced/consumed is internal to SSLEngine and must be exchanged with the peer before application data will be produced/consumed. The application is responsible for all data transportation.

    The application, shown on the left, supplies application (plaintext) data in an application buffer and passes it to SSLEngine . After handshaking has completed and cryptographic parameters have been negotiated, the SSLEngine object consumes the data contained in the outbound application data buffer to produce TLS/DTLS encoded data and places it in the network buffer supplied by the application. The application is now responsible for sending the contents of the outbound network buffer to the peer using the transport mechanism. Upon receiving TLS/DTLS encoded data from its peer (via the transport), the application places the inbound data into a network buffer and passes it to SSLEngine . The SSLEngine object processes the network buffer's contents to produce application data (or handshake data, which is consumed internally).

    An instance of the SSLEngine class can be in one of the following states: Creation

    The SSLEngine has been created and initialized, but has not yet been used. During this phase, an application may set any SSLEngine -specific settings (enabled cipher suites, whether the SSLEngine should handshake in client or server mode, and so on). Once handshaking has begun, though, any new settings (except client/server mode) will be used for the next handshake. Initial handshaking
    The initial handshake is a procedure by which the two peers exchange communication parameters until an SSLSession is established. Application data can’t be sent during this phase. Application data
    After the communication parameters have been established and the handshake is complete, application data can flow through the SSLEngine . Outbound application messages are encrypted and integrity protected, and inbound messages reverse the process. Rehandshaking
    Either side can request a renegotiation of the session at any time during the Application Data phase. New handshaking data can be intermixed among the application data. Before starting the rehandshake phase, the application may reset the TLS/DTLS communication parameters such as the list of enabled cipher suites and whether to use client authentication, but can not change between client/server modes. As before, after handshaking has begun, any new SSLEngine configuration settings won’t be used until the next handshake. Closure
    When the connection is no longer needed, the application should close the SSLEngine and should send/receive any remaining messages to the peer before closing the underlying transport mechanism. Once an engine is closed, it is not reusable: a new SSLEngine must be created.
    SSLEngine Methods

    There are three types of SSLEngine methods: those that initialize the SSLEngine and start the handshake, those that process data packets for writing to or reading from the network, and those that properly close the SSLEngine and connection.

    The following steps describe the handshake process with respect to the methods of SSLEngine :

  • After you have created the SSLEngine , call the various set* methods to configure all aspects of the connection that is about to occur (for example, setEnabledProtocols() , setEnabledCipherSuites() , setUseClientMode() , and setWantClientAuth() ). You can also configure the connection with the SSLParameters class, which enables you to set multiple settings in a single method call.
  • Obtain the currently empty SSLSession for the SSLEngine , then determine the maximum buffer sizes for the application and network bytes that could be generated with the getApplicationBufferSize() and getPacketBufferSize() methods. Allocate ByteBuffer instances for application and network buffers accordingly.
  • Once you have configured the connection and the buffers, call the beginHandshake() method, which moves the SSLEngine into the initial handshaking state.
  • Create the transport mechanism that the connection will use with, for example, the SocketChannel or Socket classes.

    Call the wrap() and unwrap() methods to perform the initial handshaking. You'll need to call these methods several times before application data can be consumed, produced, and properly protected by later wrap() / unwrap() calls.

    The handshake bytes must be exchanged with the peer using the transport mechanism. For more information about the TLS handshaking mechanism, see one of the TLS RFCs (such as RFC 5246: The Transport Layer Security (TLS) Protocol: Version 1.2 ).

    For example, if your SSLEngine is acting as a client and handshaking using TLSv1.2, then you might see the following occurring:

  • The wrap() method produces a TLS ClientHello message, then places it in the outbound network buffer. The application must correctly send the bytes of this message to the peer.
  • The SSLEngine must now process the peer's response (such as the ServerHello, Certificate, and ServerHelloDone messages) to drive the handshake forward. The application obtains the response bytes from the network transport and places them in the inbound network buffer. The SSLEngine processes these bytes using the unwrap() method.
  • The SSLEngine sends more handshaking data (such as the ChangeCipherSuite and Finished messages). The wrap() places the bytes of the message in the outbound network buffer. The application must correctly send these bytes to the peer as before.
  • The SSLEngine waits for its peer's ChangeCipherSuite or Finished message. The bytes of this message follow the same path as in Step b.
  • Once the handshaking has completed, application data can now start flowing. Call the wrap() method to take the bytes from the outbound application buffer, encrypt and protect them, and then place them in the network buffer for transport to the peer. Likewise, call the unwrap() method to decrypt and unprotect inbound network data. The resulting application data is placed in the inbound application data buffer.
  • Once data has been exchanged between the two peers, close both the inbound and outbound sides of the SSLEngine . Call the closeOutbound() method to signal the SSLEngine that the application will not be sending any more data. Call the closeInbound() method to signal the SSLEngine that the network connection has been closed and there will be no more data.

    To indicate the status of the engine and what actions the application should take, the SSLEngine.wrap() and SSLEngine.unwrap() methods return an SSLEngineResult instance, as shown in Example 8-5 . This SSLEngineResult object contains two pieces of status information: the overall status of the engine and the handshaking status.

    The possible overall statuses are represented by the SSLEngineResult.Status enum. The following statuses are available:

    There was no error.
    CLOSED
    The operation closed the SSLEngine or the operation could not be completed because it was already closed. BUFFER_UNDERFLOW
    The input buffer had insufficient data to process, indicating that the application must obtain more data from the peer (for example, by reading more data from the network) and try the operation again.
    BUFFER_OVERFLOW
    The output buffer had insufficient space to hold the result, indicating that the application must clear or enlarge the destination buffer and try the operation again.

    Example 8-1 illustrates how to handle the BUFFER_UNDERFLOW and BUFFER_OVERFLOW statuses of the SSLEngine.unwrap() method. It uses SSLSession.getApplicationBufferSize() and SSLSession.getPacketBufferSize() to determine how large to make the byte buffers.

    The possible handshaking statuses are represented by the SSLEngineResult.HandshakeStatus enum. They represent whether handshaking has completed, whether the caller must send or receive more handshaking data from the peer, and so on. The following handshake statuses are available: FINISHED

    The SSLEngine has just finished handshaking. NEED_TASK
    The SSLEngine needs the results of one (or more) delegated tasks before handshaking can continue. NEED_UNWRAP
    The SSLEngine needs to receive data from the remote side before handshaking can continue. NEED_UNWRAP_AGAIN
    The SSLEngine needs to unwrap before handshaking can continue. This value indicates that not-yet-interpreted data has been previously received from the remote side and does not need to be received again; the data has been brought into the JSSE framework but has not been processed yet. NEED_WRAP
    The SSLEngine must send data to the remote side before handshaking can continue, so SSLEngine.wrap() should be called. NOT_HANDSHAKING
    The SSLEngine is not currently handshaking.

    Having two statuses per result allows the SSLEngine to indicate that the application must take two actions: one in response to the handshaking and one representing the overall status of the wrap() and unwrap() methods. For example, the engine might, as the result of a single SSLEngine.unwrap() call, return SSLEngineResult.Status.OK to indicate that the input data was processed successfully and SSLEngineResult.HandshakeStatus.NEED_UNWRAP to indicate that the application should obtain more TLS/DTLS encoded data from the peer and supply it to SSLEngine.unwrap() again so that handshaking can continue. As you will see, the following examples are greatly simplified; they would need to be expanded significantly to properly handle all of these status combinations.

    Example 8-2 and Example 8-3 illustrate how to process handshaking data by checking handshaking status and the overall status of the wrap() and unwrap() methods.

    Example 8-1 Sample Code for Handling BUFFER_UNDERFLOW and BUFFER_OVERFLOW

    The following code sample illustrates how to handle BUFFER_UNDERFLOW and BUFFER_OVERFLOW status:

        SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
        switch (res.getStatus()) {
            case BUFFER_OVERFLOW:
                // Maybe need to enlarge the peer application data buffer if
                // it is too small, and be sure you've compacted/cleared the
                // buffer from any previous operations.
                if (engine.getSession().getApplicationBufferSize() > peerAppData.capacity()) {
                    // enlarge the peer application data buffer
                } else {
                    // compact or clear the buffer
                // retry the operation
             break;
             case BUFFER_UNDERFLOW:
                 // Not enough inbound data to process. Obtain more network data
                 // and retry the operation. You may need to enlarge the peer
                 // network packet buffer, and be sure you've compacted/cleared
                 // the buffer from any previous operations.
                 if (engine.getSession().getPacketBufferSize() > peerNetData.capacity()) {
                     // enlarge the peer network packet buffer
                 } else {
                     // compact or clear the buffer
                 // obtain more inbound network data and then retry the operation
                 break; 
             // Handle other status: CLOSED, OK
             // ...
                               

    Example 8-2 Sample Code for Checking and Processing Handshaking Statuses and Overall Statuses

    The following code sample illustrates how to process handshaking data by checking handshaking status and the overall status of the wrap() and unwrap() methods:

    void doHandshake(SocketChannel socketChannel, SSLEngine engine,
        ByteBuffer myNetData, ByteBuffer peerNetData) throws Exception {
        // Create byte buffers to use for holding application data
        int appBufferSize = engine.getSession().getApplicationBufferSize();
        ByteBuffer myAppData = ByteBuffer.allocate(appBufferSize);
        ByteBuffer peerAppData = ByteBuffer.allocate(appBufferSize);
        // Begin handshake
        engine.beginHandshake();
        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
        // Process handshaking message
        while (hs != SSLEngineResult.HandshakeStatus.FINISHED &&
            hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
            switch (hs) {
            case NEED_UNWRAP:
                // Receive handshaking data from peer
                if (socketChannel.read(peerNetData) < 0) {
                    // The channel has reached end-of-stream
                // Process incoming handshaking data
                peerNetData.flip();
                SSLEngineResult res = engine.unwrap(peerNetData, peerAppData);
                peerNetData.compact();
                hs = res.getHandshakeStatus();
                // Check status
                switch (res.getStatus()) {
                case OK :
                    // Handle OK status
                    break;
                   // Handle other status: BUFFER_UNDERFLOW, BUFFER_OVERFLOW, CLOSED
                   // ...
                break;
            case NEED_WRAP:
                // Ensure that any previous net data in myNetData has been sent
                // to the peer (not shown here), then generate more.
                // Empty/clear the local network packet buffer.        
                myNetData.clear();
                // Generate more data to send if possible.
                res = engine.wrap(myAppData, myNetData);
                hs = res.getHandshakeStatus();
                // Check status
                switch (res.getStatus()) {
                case OK :
                    myNetData.flip();
                    // Send the handshaking data to peer
                    while (myNetData.hasRemaining()) {
                        socketChannel.write(myNetData);
                    break;
                    // Handle other status:  BUFFER_OVERFLOW, BUFFER_UNDERFLOW, CLOSED
                    // ...
                break;
            case NEED_TASK :
                // Handle blocking tasks
                break;
                // Handle other status:  // FINISHED or NOT_HANDSHAKING
                // ...
        // Processes after handshaking
        // ...
                               

    Example 8-3 Sample Code for Handling DTLS handshake Status and Overall Status

    The following code sample illustrates how to handle DTLS handshake status:

    void handshake(SSLEngine engine, DatagramSocket socket,
                   SocketAddress peerAddr) throws Exception {
        boolean endLoops = false;
        // private static int MAX_HANDSHAKE_LOOPS = 60;
        int loops = MAX_HANDSHAKE_LOOPS;
        engine.beginHandshake();
        while (!endLoops && (serverException == null) && (clientException == null)) {
            if (--loops < 0) {
                throw new RuntimeException("Too many loops to produce handshake packets");
            SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
            if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
                    hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
                ByteBuffer iNet;
                ByteBuffer iApp;
                if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
                    // receive ClientHello request and other SSL/TLS/DTLS records
                    byte[] buf = new byte[1024];
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    try {
                        socket.receive(packet);
                    } catch (SocketTimeoutException ste) {
                        // retransmit the packet if timeout
                        List <DatagramPacket> packets =
                            onReceiveTimeout(engine, peerAddr);
                        for (DatagramPacket p : packets) {
                            socket.send(p);
                        continue;
                    iNet = ByteBuffer.wrap(buf, 0, packet.getLength());
                    iApp = ByteBuffer.allocate(1024);
                } else {
                    iNet = ByteBuffer.allocate(0);
                    iApp = ByteBuffer.allocate(1024);
                SSLEngineResult r = engine.unwrap(iNet, iApp);
                SSLEngineResult.Status rs = r.getStatus();
                hs = r.getHandshakeStatus();
                if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                    // the client maximum fragment size config does not work?
                    throw new Exception("Buffer overflow: " +
                                        "incorrect client maximum fragment size");
                } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                    // bad packet, or the client maximum fragment size
                    // config does not work?
                    if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
                        throw new Exception("Buffer underflow: " +
                                            "incorrect client maximum fragment size");
                    } // otherwise, ignore this packet
                } else if (rs == SSLEngineResult.Status.CLOSED) {
                    endLoops = true;
                }   // otherwise, SSLEngineResult.Status.OK:
                if (rs != SSLEngineResult.Status.OK) {
                    continue;
            } else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
                List <DatagramPacket> packets =
                    // Call a function to produce handshake packets
                    produceHandshakePackets(engine, peerAddr);
                for (DatagramPacket p : packets) {
                    socket.send(p);
            } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
                runDelegatedTasks(engine);
            } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
                // OK, time to do application data exchange.
                endLoops = true;
            } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
                endLoops = true;
        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
        if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
            throw new Exception("Not ready for application data yet");
                      
    SSLEngine for TLS Protocols

    This section shows you how to create an SSLEngine object and use it to generate and process TLS data.

        import javax.net.ssl.*;
        import java.security.*;
        // Create and initialize the SSLContext with key material
        char[] passphrase = "passphrase".toCharArray();
        // First initialize the key and trust material
        KeyStore ksKeys = KeyStore.getInstance("JKS");
        ksKeys.load(new FileInputStream("testKeys"), passphrase);
        KeyStore ksTrust = KeyStore.getInstance("JKS");
        ksTrust.load(new FileInputStream("testTrust"), passphrase);
        // KeyManagers decide which key material to use
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
        kmf.init(ksKeys, passphrase);
        // TrustManagers decide whether to allow connections
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
        tmf.init(ksTrust);
        // Get an instance of SSLContext for TLS protocols
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        // Create the engine
        SSLEngine engine = sslContext.createSSLengine(hostname, port);
        // Use as client
        engine.setUseClientMode(true);
                               

    The two main SSLEngine methods are wrap() and unwrap(). They are responsible for generating and consuming network data respectively. Depending on the state of the SSLEngine object, this data might be handshake or application data.

    Performing TLS Handshake, Then Processing TLS Data, With SSLEngine.wrap() and SSLEngine.unwrap()

    Each SSLEngine object has several phases during its lifetime. Before application data can be sent or received, the TLS protocol requires a handshake to establish cryptographic parameters. This handshake requires a series of back-and-forth steps by the SSLEngine object. During the initial handshaking, the wrap() and unwrap() methods generate and consume handshake data before starting to exchange application data.

    The application is responsible for reliably transporting the data (for example, by using TCP) to and from the peer. That is, your application (and not SSLEngine) must reliably deliver to the peer any data generated by the wrap() method, and your application (and not SSLEngine) must reliably obtain data from the peer so that it can decode it by calling the unwrap() method.

    Each SSLEngine operation generates an instance of the SSLEngineResult class, in which the SSLEngineResult.HandshakeStatus field is used to determine what operation must occur next to move the handshake along.

    When handshaking is complete, further calls to wrap() will attempt to consume application data and package it for transport. The unwrap() method will attempt the opposite.

    To send data to the peer, the application first supplies the data that it wants to send via SSLEngine.wrap() to obtain the corresponding TLS encoded data. The application then sends the encoded data to the peer using its chosen transport mechanism. When the application receives the TLS encoded data from the peer via the transport mechanism, it supplies this data to the SSLEngine via SSLEngine.unwrap() to obtain the plaintext data sent by the peer.

    Figure 8-3 shows the state machine during a typical TLS handshake, with corresponding messages and statuses:

    Figure 8-3 State Machine during TLS Handshake

    Description of Figure 8-3 follows
    Description of "Figure 8-3 State Machine during TLS Handshake"

    Create ByteBuffer instances to represent the application data buffer and the network data buffer on the client and server. In the client's and server's outbound application data buffers, specify the data that you want encrypted and sent over the network to the server and client, respectively.

    Note:

    In the wrap(ByteBuffer src, ByteBuffer dst) method, the parameter src is the application data buffer and dst is the network data buffer. Conversely, in the unwrap(ByteBuffer src, ByteBuffer dst) method, the parameter src is the network data buffer and dst is the application data buffer. Both wrap() and unwrap() return an instance of SSLEngineResult, which contains a SSLEngineResult.HandshakeStatus field that indicates whether the handshake is complete or what must occur next to move the handshake along.

    In a loop, call wrap() and unwrap() on the client and server as follows, until the handshake is complete and both the client and server have sent their application data to each other:

    Call wrap() on the client and the server. Check the value of the SSLEngineResult.HandshakeStatus field in the SSLEngineResult instance that wrap() returns:

  • If the handshake isn't complete, then the parameter dst will contain handshake data that has to be sent over the network to the peer.
  • If the handshake is complete, then dst will contain application data encrypted by SSLEngine, ready to be sent to the remote peer.

    Add code to handle the SSLEngineResult.HandshakeStatus value returned by the wrap() and unwrap() methods. See Understanding SSLEngine Operation Statuses for more information.

    If the wrap() method generated data in the network data buffer (which can contain either handshake data or encrypted application data), then send it over the network to the remote peer.

    Note:

  • It is the responsibility of your application, not SSLEngine, to send data in the network data buffer to the remote peer.
  • After you call wrap(), you must ensure that all data in the network data buffer has been sent to the peer.

    For example, Example 8-2 sends network data to the remote peer by calling SocketChannel.write(). It checks that all network data has been sent by calling ByteBuffer.hasRemaining():

                    while (myNetData.hasRemaining()) {
                        socketChannel.write(myNetData);
                                              

    Obtain network data sent over the network by the remote peer. Note that it's the responsibility of your application, not SSLEngine, to do this. For example, Example 8-2 obtains network data from the remote peer by calling SocketChannel.read():

            case NEED_UNWRAP:
                // Receive handshaking data from peer
                if (socketChannel.read(peerNetData) < 0) {
                    // The channel has reached end-of-stream
                                              

    With the network data obtained from the remote peer, call unwrap() on the client and the server. Check the value of the SSLEngineResult.HandshakeStatus field in the SSLEngineResult instance that unwrap() returns:

  • If the handshake isn't complete, then the src parameter may contain additional handshake packets, or more packets will need to be obtained from the peer to continue the handshake.
  • If the handshake is complete, then dst may contain application data decrypted by SSLEngine, ready to be processed by the application.

    Ensure that the client and server handles the SSLEngineResult.HandshakeStatus value returned by unwrap().

    Example 8-5 Sample Code for Creating a Nonblocking SocketChannel

    The following example is an SSL application that uses a non-blocking SocketChannel to communicate with its peer. It sends the string "hello" to the peer by encoding it using the SSLEngine created in Example 8-4 . It uses information from the SSLSession to determine how large to make the byte buffers.

    Note:

    The example can be made more robust and scalable by using a Selector with the nonblocking SocketChannel.
  •     // Create a nonblocking socket channel
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress(hostname, port));
        // Complete connection
        while (!socketChannel.finishedConnect()) {
            // do something until connect completed
        // Create byte buffers for holding application and encoded data
        SSLSession session = engine.getSession();
        ByteBuffer myAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
        ByteBuffer myNetData = ByteBuffer.allocate(session.getPacketBufferSize());
        ByteBuffer peerAppData = ByteBuffer.allocate(session.getApplicationBufferSize());
        ByteBuffer peerNetData = ByteBuffer.allocate(session.getPacketBufferSize());
        // Do initial handshake
        doHandshake(socketChannel, engine, myNetData, peerNetData);
        myAppData.put("hello".getBytes());
        myAppData.flip();
        while (myAppData.hasRemaining()) {
            // Generate TLS/DTLS encoded data (handshake or application data)
            SSLEngineResult res = engine.wrap(myAppData, myNetData);
            // Process status of call
            if (res.getStatus() == SSLEngineResult.Status.OK) {
                myAppData.compact();
                // Send TLS/DTLS encoded data to peer
                while(myNetData.hasRemaining()) {
                    int num = socketChannel.write(myNetData);
                    if (num == 0) {
                        // no bytes written; try again later
            // Handle other status:  BUFFER_OVERFLOW, CLOSED
                                  

    Example 8-6 Sample Code for Reading Data From Nonblocking SocketChannel

    The following sample code illustrates how to read data from the same nonblocking SocketChannel and extract the plaintext data from it by using SSLEngine created in Example 8-4. Each iteration of this code may or may not produce plaintext data, depending on whether handshaking is in progress.
        // Read TLS/DTLS encoded data from peer
        int num = socketChannel.read(peerNetData);
        if (num == -1) {
            // The channel has reached end-of-stream
        } else if (num == 0) {
            // No bytes read; try again ...
        } else {
            // Process incoming data
            peerNetData.flip();
            res = engine.unwrap(peerNetData, peerAppData);
            if (res.getStatus() == SSLEngineResult.Status.OK) {
                peerNetData.compact();
            if (peerAppData.hasRemaining()) {
                // Use peerAppData
        // Handle other status:  BUFFER_OVERFLOW, BUFFER_UNDERFLOW, CLOSED
                      
    SSLEngine for DTLS Protocols

    This section shows you how to create an SSLEngine object and use it to handle a DTLS handshake, generate and process DTLS data, and handle retransmissions in DTLS connections.

    Creating an SSLEngine Object for DTLS

    The following examples illustrate how to create an SSLEngine object for DTLS.

    Note:

    The server name and port number are not used for communicating with the server (all transport is the responsibility of the application). They are hints to the JSSE provider to use for DTLS session caching, and for Kerberos-based cipher suite implementations to determine which server credentials should be obtained.

    Example 8-7 Sample Code for Creating an SSLEngine Client for DTLS with PKCS12 as Keystore

    The following sample code creates an SSLEngine client for DTLS that uses PKCS12 as keystore:

        import javax.net.ssl.*;
        import java.security.*;
        // Create and initialize the SSLContext with key material
        char[] passphrase = "passphrase".toCharArray();
        // First initialize the key and trust material
        KeyStore ksKeys = KeyStore.getInstance("PKCS12");
        ksKeys.load(new FileInputStream("testKeys"), passphrase);
        KeyStore ksTrust = KeyStore.getInstance("PKCS12");
        ksTrust.load(new FileInputStream("testTrust"), passphrase);
        // KeyManagers decide which key material to use
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
        kmf.init(ksKeys, passphrase);
        // TrustManagers decide whether to allow connections
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
        tmf.init(ksTrust);
        // Get an instance of SSLContext for DTLS protocols
        sslContext = SSLContext.getInstance("DTLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        // Create the engine
        SSLEngine engine = sslContext.createSSLengine(hostname, port);
        // Use engine as client
        engine.setUseClientMode(true);
                                  

    Example 8-8 Sample Code for Creating an SSLEngine Server for DTLS with PKCS12 as Keystore

    The following sample code creates an SSLEngine server for DTLS that uses PKCS12 as keystore:
        import javax.net.ssl.*;
        import java.security.*;
        // Create and initialize the SSLContext with key material
        char[] passphrase = "passphrase".toCharArray();
        // First initialize the key and trust material
        KeyStore ksKeys = KeyStore.getInstance("PKCS12");
        ksKeys.load(new FileInputStream("testKeys"), passphrase);
        KeyStore ksTrust = KeyStore.getInstance("PKCS12");
        ksTrust.load(new FileInputStream("testTrust"), passphrase);
        // KeyManagers decide which key material to use
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("PKIX");
        kmf.init(ksKeys, passphrase);
        // TrustManagers decide whether to allow connections
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
        tmf.init(ksTrust);
        // Get an SSLContext for DTLS Protocol without authentication
        sslContext = SSLContext.getInstance("DTLS");
        sslContext.init(null, null, null);
        // Create the engine
        SSLEngine engine = sslContext.createSSLeEngine(hostname, port);
        // Use the engine as server
        engine.setUseClientMode(false);
        // Require client authentication
        engine.setNeedClientAuth(true);
    Generating and Processing DTLS Data

    A DTLS handshake and a TLS handshake generate and process data similarly. (See Generating and Processing TLS Data.) They both use the SSLEngine.wrap() and SSLEngine.wrap() methods to generate and consume network data, respectively.

    The following diagram shows the state machine during a typical DTLS handshake, with corresponding messages and statuses:

    Figure 8-4 State Machine during DTLS Handshake

    Description of Figure 8-4 follows
    Description of "Figure 8-4 State Machine during DTLS Handshake"

    Example 8-9 Sample Code for Handling DTLS Handshake Status and Overall Status

    This sample demonstrates how to handle DTLS handshake status (from the SSLEngine.getHandshakeStatus method) and overall status (from the SSLEngineResult.getStatus method).

    void handshake(SSLEngine engine, DatagramSocket socket, SocketAddress peerAddr) throws Exception {
        boolean endLoops = false;
        // private static int MAX_HANDSHAKE_LOOPS = 60;
        int loops = MAX_HANDSHAKE_LOOPS;
        engine.beginHandshake();
        while (!endLoops && (serverException == null) && (clientException == null)) {
            if (--loops < 0) {
                throw new RuntimeException("Too many loops to produce handshake packets");
            SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
            if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
                    hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
                ByteBuffer iNet;
                ByteBuffer iApp;
                if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
                    // Receive ClientHello request and other SSL/TLS/DTLS records
                    byte[] buf = new byte[1024];
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    try {
                        socket.receive(packet);
                    } catch (SocketTimeoutException ste) {
                        // Retransmit the packet if timeout
                        List <DatagramPacket> packets = onReceiveTimeout(engine, peerAddr);
                        for (DatagramPacket p : packets) {
                            socket.send(p);
                        continue;
                    iNet = ByteBuffer.wrap(buf, 0, packet.getLength());
                    iApp = ByteBuffer.allocate(1024);
                } else {
                    iNet = ByteBuffer.allocate(0);
                    iApp = ByteBuffer.allocate(1024);
                SSLEngineResult r = engine.unwrap(iNet, iApp);
                SSLEngineResult.Status rs = r.getStatus();
                hs = r.getHandshakeStatus();
                if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
                    // The client maximum fragment size config does not work?
                    throw new Exception("Buffer overflow: " +
                                        "incorrect client maximum fragment size");
                } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
                    // Bad packet, or the client maximum fragment size
                    // config does not work?
                    if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
                        throw new Exception("Buffer underflow: " +
                                            "incorrect client maximum fragment size");
                    } // Otherwise, ignore this packet
                } else if (rs == SSLEngineResult.Status.CLOSED) {
                    endLoops = true;
                } // Otherwise, SSLEngineResult.Status.OK
                if (rs != SSLEngineResult.Status.OK) {
                    continue;
            } else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
                // Call a function to produce handshake packets
                List <DatagramPacket> packets = produceHandshakePackets(engine, peerAddr);
                for (DatagramPacket p : packets) {
                    socket.send(p);
            } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
                runDelegatedTasks(engine);
            } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
                // OK, time to do application data exchange
                endLoops = true;
            } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
                endLoops = true;
        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
        if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
            throw new Exception("Not ready for application data yet");
                                  

    Difference Between the TLS and DTLS SSLEngine.wrap() Methods

    The SSLEngine.wrap() method for DTLS is different from TLS as follows:

    In the TLS implementation of SSLEngine, the output buffer of SSLEngine.wrap() contains one or more TLS records (due to the TLSv1 BEAST Cipher Block Chaining vulnerability).

    In the DTLS implementation of SSLEngine, the output buffer of SSLEngine.wrap() contains at most one record, so that every DTLS record can be marshaled and delivered to the datagram layer individually.

    Handling Retransmissions in DTLS Connections

    In SSL/TLS over a reliable connection, data is guaranteed to arrive in the proper order, and retransmission is unnecessary. However, for DTLS, which often works over unreliable media, missing or delayed handshake messages must be retransmitted.

    The SSLEngine class operates in a completely transport-neutral manner, and the application layer performs all I/O. Because the SSLEngine class isn’t responsible for I/O, the application instead is responsible for providing timers and signalling the SSLEngine class when a retransmission is needed. The application layer must determine the right timeout value and when to trigger the timeout event. During handshaking, if an SSLEngine object is in HandshakeStatus.NEED_UNWRAP state, a call to SSLEngine.wrap() means that the previous packets were lost, and must be retransmitted. For such cases, the DTLS implementation of the SSLEngine class takes the responsibility to wrap the previous necessary handshaking messages again if necessary.

    Note:

    In a DTLS engine, only handshake messages must be properly exchanged. Application data can handle packet loss without the need for timers.
    Handling Retransmission in an Application

    SSLEngine.unwrap() and SSLEngine.wrap() can be used together to handle retransmission in an application.

    Figure 8-5 shows a typical scenario for handling DTLS handshaking retransmission:

    Figure 8-5 DTLS Handshake Retransmission State Flow

    This image illustrates the DTLS handshake retransmission state flow. The flow is described in the numbered steps that follow the image.
  • Create and initialize an instance of DTLS SSLEngine.
    See Creating an SSLEngine Object. The DTLS handshake process begins.
  • If the handshake status is HandshakeStatus.NEED_UNWRAP, wait for data from network.
  • If the timer times out, it indicates that the previous delivered handshake messages may have been lost.

    Note:

    In DTLS handshaking retransmission, the determined handshake status isn’t necessarily HandshakeStatus.NEED_WRAP for the call to SSLEngine.wrap().
  • Call SSLEngine.wrap().
  • The wrapped packets are delivered.
  • Optional: If the handshake status is HandshakeStatus.NEED_UNWRAP, wait for data from network.
  • Optional: If you received the network data, call SSLEngine.unwrap().
  • Determine the handshake status for next processing. The handshake status can be HandshakeStatus.NEED_UNWRAP_AGAIN, HandshakeStatus.NEED_UNWRAP, or HandshakeStatus.NEED_WRAP.
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:47.947 EDT|CertificateRequest.java:864|Consuming CertificateRequest handshake message (
    "CertificateRequest": {
      "certificate_request_context": "",
      "extensions": [
        "signature_algorithms (13)": {
          "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
        "signature_algorithms_cert (50)": {
          "signature schemes": [ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384, ecdsa_secp512r1_sha512, rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512, rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512, dsa_sha256, ecdsa_sha1, rsa_pkcs1_sha1, dsa_sha1]
                               

    Read Server’s Certificate Message

    The Certificate message contains the authentication certificate and any other supporting certificates in the certificate chain. It specifies the following:

  • certificate_request_context: For server authentication, this field is empty
  • certificate_list: Contains a certificate chain signed by a signature algorithm advertised by the client. However, in this example, a self-signed certificate (a certificate whose subject and issue name are identical) was received. This same self-signed certificate was discovered earlier during initialization, so it will be trusted when the TrustManager is actually called to verify the received certificate.
  • There are many different ways of establishing trust, so if the default X509TrustManager is not doing the types of trust management you need, you can supply your own X509TrustManager to SSLContext.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:47.964 EDT|CertificateMessage.java:1148|Consuming server Certificate handshake message (
    "Certificate": {
      "certificate_request_context": "",
      "certificate_list": [  
        "certificate" : {
          "version"            : "v1",
          "serial number"      : "41 00 44 46",
          "signature algorithm": "MD5withRSA",
          "issuer"             : "CN=localhost, OU=Widget Development Group, O="Ficticious Widgets, Inc.", L=Sunnyvale, ST=CA, C=US",
          "not before"         : "2004-07-22 18:48:38.000 EDT",
          "not  after"         : "2011-05-22 18:48:38.000 EDT",
          "subject"            : "CN=localhost, OU=Widget Development Group, O="Ficticious Widgets, Inc.", L=Sunnyvale, ST=CA, C=US",
          "subject public key" : "RSA"}
        "extensions": {
          <no extension>
    ...

    The client recognizes this certificate and can trust it.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.165 EDT|X509TrustManagerImpl.java:242|Found trusted certificate (
      "certificate" : {
        "version"            : "v1",
        "serial number"      : "41 00 44 46",
        "signature algorithm": "MD5withRSA",
        "issuer"             : "CN=localhost, OU=Widget Development Group, O="Ficticious Widgets, Inc.", L=Sunnyvale, ST=CA, C=US",
        "not before"         : "2004-07-22 18:48:38.000 EDT",
        "not  after"         : "2011-05-22 18:48:38.000 EDT",
        "subject"            : "CN=localhost, OU=Widget Development Group, O="Ficticious Widgets, Inc.", L=Sunnyvale, ST=CA, C=US",
        "subject public key" : "RSA"}
                               

    Read Server’s CertificateVerify Message

    The certificate sent by the server is verified by the CertificateVerify message. The message is used to provide explicit proof that the server has the private key corresponding to its certificate. This message specifies the following:

    Signature algorithm: The signature algorithm used; in this example, it is rsa_pss_rsae_sha256.

    Signature: The signature over the entire handshake using the private key corresponding to the public key in the Certificate message

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.194 EDT|CertificateVerify.java:1128|Consuming CertificateVerify handshake message (
    "CertificateVerify": {
      "signature algorithm": rsa_pss_rsae_sha256
      "signature": {
        0000: 0F 25 DD 62 03 6B 8C 8F   22 C7 8D 46 A2 A6 45 39  .%.b.k.."..F..E9
        0010: 08 8D 51 1E 48 52 66 A4   F8 28 D3 FD 18 93 70 C6  ..Q.HRf..(....p.
        0020: 32 74 C1 CC 0A C4 60 41   50 AF 7C DA 0C DB 92 F9  2t....`AP.......
        0030: 14 CB EF 15 7F 3E 52 16   F7 CC 8A 7C C9 1F 42 CA  .....>R.......B.
        0040: 90 8D FA B7 F2 3A 46 7E   F7 9F 43 CE C6 AA 15 59  .....:F...C....Y
        0050: EE AD 34 10 FF B7 BC FD   A2 F7 F3 1A FA 7F 26 61  ..4...........&a
        0060: 80 2B 50 3A 8A 9E 5C 0E   4C A6 24 DA E6 3D 71 FA  .+P:..\.L.$..=q.
        0070: AE 78 79 D2 DA 36 DE C1   A6 BC 18 46 04 CE 03 4E  .xy..6.....F...N
                               

    Read Server’s Finished Message

    The server sends a Finished message. This message contains a Message Authentication Code (MAC) over the entire handshake.

    javax.net.ssl|DEBUG|01|main|2018-08-17 01:56:26.764 EDT|Finished.java:860|Consuming server Finished handshake message (
    "Finished": {
      "verify data": {
        0000: CA 7B 74 A6 79 36 ED 62   A7 0E 14 9D 9F D0 4A 0F  ..t.y6.b......J.
        0010: 02 4C 78 BB E2 89 A2 C6   E8 BD 28 CA E7 D9 DB 68  .Lx.......(....h
                               

    Send Certificate Message

    The client sends a Certificate message because the server requested client authentication through a CertificateRequest message. The certificate message specifies similar information as the server’s Certificate message. The client needs to send credentials back to the sever, so its X509KeyManager is consulted. The client looks for a match between the list of accepted issuers and the certificates that are in the KeyStore. In this case, there is a match: the client has the credentials for "duke". It's now up to the server's X509TrustManager to decide whether to accept these credentials.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.222 EDT|CertificateMessage.java:1116|Produced client Certificate message (
    "Certificate": {
      "certificate_request_context": "",
      "certificate_list": [  
        "certificate" : {
          "version"            : "v1",
          "serial number"      : "3B 0A FA 66",
          "signature algorithm": "MD5withRSA",
          "issuer"             : "CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Cupertino, ST=CA, C=US",
          "not before"         : "2001-05-22 19:46:46.000 EDT",
          "not  after"         : "2011-05-22 19:46:46.000 EDT",
          "subject"            : "CN=Duke, OU=Java Software, O="Sun Microsystems, Inc.", L=Cupertino, ST=CA, C=US",
          "subject public key" : "RSA"}
        "extensions": {
          <no extension>
                               

    Send CertificateVerify Message

    As with the CertificateVerify message sent by the server, the certificate sent by the client is verified by the CertificateVerify message. The message is used to provide explicit proof that the client has the private key corresponding to its certificate.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.268 EDT|CertificateVerify.java:1097|Produced client CertificateVerify handshake message (
    "CertificateVerify": {
      "signature algorithm": rsa_pss_rsae_sha256
      "signature": {
        0000: 91 C2 F7 5D 8D 90 B4 82   E4 BA C6 23 08 E2 B4 DD  ...].......#....
        0010: 8D 95 8F 9F 31 4F 26 F3   97 3B FB 5B 10 4D AE F6  ....1O&..;.[.M..
        0020: 71 78 FB 7B 3A 4F F6 1B   BF D2 E3 FB BE 53 F6 70  qx..:O.......S.p
        0030: 7E 73 83 F4 9A 5E 08 19   63 C1 97 4C 10 B1 C7 3F  .s...^..c..L...?
        0040: 4A 7D EF 4A 30 44 15 9F   D0 F2 8B C4 D1 45 69 B1  J..J0D.......Ei.
        0050: D9 DB 45 83 C4 11 91 B3   81 5E 69 F4 5C 2A CF 69  ..E......^i.\*.i
        0060: D3 A6 7E 75 B4 C9 30 FB   5B AC BA 9F A3 C5 0C FD  ...u..0.[.......
        0070: 9A 62 A4 DA 5A 80 6B 72   CD F5 A5 53 AD 14 74 1C  .b..Z.kr...S..t.
                               

    Send Finished Message

    The client then sends its Finished message to the sever:

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.271 EDT|Finished.java:658|Produced client Finished handshake message (
    "Finished": {
      "verify data": {
        0000: 93 04 B5 23 8F 48 3A CF   4A 85 35 9E 5F E0 1D 4C  ...#.H:.J.5._..L
        0010: 9C 65 06 D4 E8 B4 ED 8F   01 6B 1E A2 DD 18 BD 78  .e.......k.....x
    ...

    The client and server have verified the Finished messages that they have received from their peers. Both sides may now send and receive application data over the connection.

    Exchange Application Data, Client Sends GET Command

    The server and client are ready to exchange application data. The client sends a "GET /index.html HTTP1.0" command.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.375 EDT|SSLCipher.java:2019|Plaintext before ENCRYPTION (
      0000: 47 45 54 20 2F 69 6E 64   65 78 2E 68 74 6D 6C 20  GET /index.html 
      0010: 48 54 54 50 2F 31 2E 30   0D 0A 0D 0A 17 00 00 00  HTTP/1.0........
      0020: 00 00 00 00 00 00 00 00   00 00 00 00 00           .............
    ...

    Note that data over the wire is encrypted:

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.385 EDT|SSLSocketOutputRecord.java:295|Raw write (
      0000: 17 03 03 00 3D 90 BF D1   81 E6 A3 E7 DA 50 A9 8B  ....=........P..
      0010: 18 F5 4B 30 AE 59 41 81   25 C4 9E 3E 70 29 5D C6  ..K0.YA.%..>p)].
      0020: 64 49 0B 4A 0E 93 E3 8F   DC 42 BA B5 21 42 38 88  dI.J.....B..!B8.
      0030: 62 4D 0C 86 FE 9A 8C B9   95 EF 89 93 61 3C 13 69  bM..........a<.i
      0040: 6C 45                                              lE
                               

    Read NewSessionTicket Message

    After the server receives the client’s Finished message, it can send a NewSessionTicket message anytime, which contains a PSK ticket that the client can use for speeding up future handshakes.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.517 EDT|NewSessionTicket.java:330|Consuming NewSessionTicket message (
    "NewSessionTicket": {
      "ticket_lifetime"      : "86,400",
      "ticket_age_add"       : "<omitted>",
      "ticket_nonce"         : "01",
      "ticket"               : "A5 30 8C B6 AD 95 79 E8 2A D1 95 C0 F0 2F 6F AA 9E 97 58 AA 3D 19 82 2D 2C 47 C0 ED BF 64 48 AB",
      "extensions"           : [
        <no extension>
    

    A duplicate SSLSession is created with the newly generated PSK information attached.

    javax.net.ssl|ALL|01|main|2018-08-18 01:04:48.517 EDT|SSLSessionImpl.java:203|Session initialized:  Session(1534568687873|TLS_AES_128_GCM_SHA256)
                               

    Exchange Application Data, Server Sends HTTPS Header and Data

    The client receives application data from the server, first the HTTPS header, then the actual data.

    javax.net.ssl|ALL|01|main|2018-08-18 01:04:48.517 EDT|SSLSessionImpl.java:203|Session initialized:  Session(1534568687873|TLS_AES_128_GCM_SHA256)
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.617 EDT|SSLSocketInputRecord.java:474|Raw read (
      0000: 17 03 03 00 63                                     ....c
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.618 EDT|SSLSocketInputRecord.java:215|READ: TLSv1.2 application_data, length = 99
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.618 EDT|SSLSocketInputRecord.java:474|Raw read (
      0000: 65 87 0E 1E 78 F7 AC C4   F7 C6 4D 55 91 6F 72 CC  e...x.....MU.or.
      0010: 18 2D 74 C3 B6 7B 2A F9   EB 2B F4 A8 C7 FD 09 FA  .-t...*..+......
      0020: 7E 36 9D F7 88 E7 44 DD   60 AF EB B0 F8 CF E1 64  .6....D.`......d
      0030: 0D 9B F4 B0 24 C2 BC B1   BF F7 F2 B6 CB E4 2E 39  ....$..........9
      0040: 78 B8 73 09 91 65 7A 0F   4C 49 DE 9A 7F 7B 42 86  x.s..ez.LI....B.
      0050: CA 33 87 DB 0D B2 E5 61   3C 70 6F F9 6A 15 A9 74  .3.....a<po.j..t
      0060: 64 E0 B0                                           d..
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.619 EDT|SSLSocketInputRecord.java:251|READ: TLSv1.2 application_data, length = 99
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.621 EDT|SSLCipher.java:1914|Plaintext after DECRYPTION (
      0000: 48 54 54 50 2F 31 2E 30   20 32 30 30 20 4F 4B 0D  HTTP/1.0 200 OK.
      0010: 0A 43 6F 6E 74 65 6E 74   2D 4C 65 6E 67 74 68 3A  .Content-Length:
      0020: 20 32 35 37 37 0D 0A 43   6F 6E 74 65 6E 74 2D 54   2577..Content-T
      0030: 79 70 65 3A 20 74 65 78   74 2F 68 74 6D 6C 0D 0A  ype: text/html..
      0040: 0D 0A                                              ..
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.626 EDT|SSLSocketInputRecord.java:215|READ: TLSv1.2 application_data, length = 2610
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.628 EDT|SSLSocketInputRecord.java:474|Raw read (
      0000: 69 8D F9 A3 E9 25 09 87   F0 E0 A1 63 12 9D 81 DF  i....%.....c....
      0010: 42 FC FA 7A 03 74 FD D5   ED 47 6C 5F 61 F2 BB 39  B..z.t...Gl_a..9
      0020: CF 64 0B B2 10 14 24 99   A3 66 8B D2 13 C9 66 FD  .d....$..f....f.
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.642 EDT|SSLSocketInputRecord.java:251|READ: TLSv1.2 application_data, length = 2610
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.647 EDT|SSLCipher.java:1914|Plaintext after DECRYPTION (
      0000: 3C 21 44 4F 43 54 59 50   45 20 68 74 6D 6C 20 50  <!DOCTYPE html P
      0010: 55 42 4C 49 43 20 22 2D   2F 2F 57 33 43 2F 2F 44  UBLIC "-//W3C//D
      0020: 54 44 20 58 48 54 4D 4C   20 31 2E 30 20 54 72 61  TD XHTML 1.0 Tra
      0030: 6E 73 69 74 69 6F 6E 61   6C 2F 2F 45 4E 22 0A 20  nsitional//EN". 
                               

    Read Server’s Alert Message

    The server sends a close_notify alert, which notifies the client that it won’t send anymore messages on this connection.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.658 EDT|Alert.java:232|Received alert message (
    "Alert": {
      "level"      : "warning",
      "description": "close_notify"
                               

    Close the Connection

    The server closes the socket and then the TLS connection.

    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.661 EDT|SSLSocketImpl.java:1161|close the underlying socket
    javax.net.ssl|DEBUG|01|main|2018-08-18 01:04:48.661 EDT|SSLSocketImpl.java:921|close the ssl connection (passive)
    javax.net.ssl|ALL|01|main|2018-08-18 01:04:48.661 EDT|SSLSocketImpl.java:658|Closing input stream
    javax.net.ssl|ALL|01|main|2018-08-18 01:04:48.661 EDT|SSLSocketImpl.java:728|Closing output stream
  • Compatibility Risks and Known Issues

    Enhancements to JSSE may introduce compatibility problems and other known issues, which are described in this section.

    TLS 1.3 Not Directly Compatible with Previous Versions

    TLS 1.3 is not directly compatible with previous versions. Although TLS 1.3 can be implemented with a backward-compatibility mode, there are still several compatibility risks to consider when upgrading to TLS 1.3:

    TLS 1.3 uses a half-close policy, while TLS 1.2 and earlier use a duplex-close policy. For applications that depend on the duplex-close policy, there may be compatibility issues when upgrading to TLS 1.3.

    The signature_algorithms_cert extension requires that pre-defined signature algorithms are used for certificate authentication. In practice, however, an application may use unsupported signature algorithms.

    The DSA signature algorithm is not supported in TLS 1.3. If a server is configured to only use DSA certificates, it cannot negotiate a TLS 1.3 connection.

    The supported cipher suites for TLS 1.3 are not the same as TLS 1.2 and earlier. If an application hardcodes cipher suites that are no longer supported, it may not be able to use TLS 1.3 without modifications to its code, for example TLS_AES_128_GCM_SHA256 (1.3 and later) versus TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (1.2 and earlier).

    The TLS 1.3 session resumption and key update behaviors are different from TLS 1.2 and earlier. The compatibility impact should be minimal, but it could be a risk if an application depends on the handshake details of the TLS protocols.

    Converting an Unsecure Socket to a Secure Socket

    Example 8-26 shows sample code that can be used to set up communication between a client and a server using unsecure sockets. This code is then modified in Example 8-27 to use JSSE to set up secure socket communication.

    Example 8-26 Socket Example Without SSL

    The following examples demonstrates server-side and client-side code for setting up an unsecure socket connection.

    In a Java program that acts as a server and communicates with a client using sockets, the socket communication is set up with code similar to the following:

    
        import java.io.*;
        import java.net.*;
        . . .
        int port = availablePortNumber;
        ServerSocket s;
        try {
            s = new ServerSocket(port);
            Socket c = s.accept();
            OutputStream out = c.getOutputStream();
            InputStream in = c.getInputStream();
            // Send messages to the client through
            // the OutputStream
            // Receive messages from the client
            // through the InputStream
        } catch (IOException e) { }
    

    The client code to set up communication with a server using sockets is similar to the following:

    
        import java.io.*;
        import java.net.*;
        . . .
        int port = availablePortNumber;
        String host = "hostname";
        try {
            s = new Socket(host, port);
            OutputStream out = s.getOutputStream();
            InputStream in = s.getInputStream();
            // Send messages to the server through
            // the OutputStream
            // Receive messages from the server
            // through the InputStream
        } catch (IOException e) { }
                            

    Example 8-27 Socket Example with SSL

    The following examples demonstrate server-side and client-side code for setting up a secure socket connection.

    In a Java program that acts as a server and communicates with a client using secure sockets, the socket communication is set up with code similar to the following. Differences between this program and the one for communication using unsecure sockets are highlighted in bold.

    
        import java.io.*;
        import javax.net.ssl.*;
        . . .
        int port = availablePortNumber;
        SSLServerSocket s;
        try {
            SSLServerSocketFactory sslSrvFact =
                (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
            s = (SSLServerSocket)sslSrvFact.createServerSocket(port);
            SSLSocket c = (SSLSocket)s.accept();
            OutputStream out = c.getOutputStream();
            InputStream in = c.getInputStream();
            // Send messages to the client through
            // the OutputStream
            // Receive messages from the client
            // through the InputStream
        catch (IOException e) {
    

    The client code to set up communication with a server using secure sockets is similar to the following, where differences with the unsecure version are highlighted in bold:

    
        import java.io.*;
        import javax.net.ssl.*;
        . . .
        int port = availablePortNumber;
        String host = "hostname";
        try {
            SSLSocketFactory sslFact =
                (SSLSocketFactory)SSLSocketFactory.getDefault();
            SSLSocket s = (SSLSocket)sslFact.createSocket(host, port);
            OutputStream out = s.getOutputStream();
            InputStream in = s.getInputStream();
            // Send messages to the server through
            // the OutputStream
            // Receive messages from the server
            // through the InputStream
        catch (IOException e) {
                            

    When you use the sample code, be aware that the sample programs are designed to illustrate how to use JSSE. They are not designed to be robust applications.

    Setting up secure communications involves complex algorithms. The sample programs provide no feedback during the setup process. When you run the programs, be patient: you may not see any output for a while. If you run the programs with the javax.net.debug system property set to all, you will see more feedback. For an introduction to reading this debug information, see Debugging TLS Connections.

    This section contains the following topics:

  • Where to Find the Sample Code
  • Sample Certificates and Keys
  • The following topics describe the samples:
  • Sample Code Illustrating a Secure Socket Connection Between a Client and a Server
  • Sample Code Illustrating HTTPS Connections
  • Sample Code Illustrating a Secure RMI Connection
  • Sample Code Illustrating the Use of an SSLEngine
  • Troubleshooting JSSE Sample Code
  • Where to Find the Sample Code

    JSSE Sample Code in the Java SE 8 documentation lists all the sample code files and text files. That page also provides a link to a ZIP file that you can download to obtain all the sample code files.

    These files are used by the code samples as the source of public/private key and certificate material. In the client program directories, the testkeys files contains the certificate entry for the Java mascot Duke. In the server program directories (./sockets/server and rmi), the file contains a certificate entry for the server localhost.

    The sample code expects the testkeys file to be in the current working directory.

    Note:

    These are very simple certificates and are not appropriate for a production environment, but they should be sufficient for running the samples here.

    The password for these keystores is: passphrase

    This truststore file is very similar to the stock JDK cacerts file, in that it contains trust certificates from several vendors. It also contains the trusted certificates from Duke and localhost.

    The password for this keystore is the same as the JDK cacert's initial password: changeit

    Please see your provider's documentation for how to configure the location of your trusted certificate file.

    Note:

    Users of the JDK can specify the location of the truststore by using one of the following methods:

    If you choose (2) or (3), be sure to replace this file with a production cacerts file before deployment.

    Ensure that you verify your cacerts file. Since you trust the CAs in the cacerts file as entities for signing and issuing certificates to other entities, you must manage the cacerts file carefully. The cacerts file should contain only certificates of the entities and CAs you trust. It is your responsibility to verify the trusted root CA certificates bundled in the cacerts file and make your own trust decisions. To remove an untrusted CA certificate from the cacerts file, use the -delete command of the keytool utility with the -cacerts option. Contact your system administrator if you do not have permission to edit this file.

    The sample programs in the samples/sockets directory illustrate how to set up a secure socket connection between a client and a server.

    When running the sample client programs, you can communicate with an existing server, such as a web server, or you can communicate with the sample server program, ClassFileServer. You can run the sample client and the sample server programs on different machines connected to the same network, or you can run them both on one machine but from different terminal windows.

    All the sample SSLSocketClient* programs in the samples/sockets/client directory (and URLReader* programs described in Sample Code Illustrating HTTPS Connections) can be run with the ClassFileServer sample server program. An example of how to do this is shown in Running SSLSocketClientWithClientAuth with ClassFileServer. You can make similar changes to run URLReader, SSLSocketClient, or SSLSocketClientWithTunneling with ClassFileServer.

    If an authentication error occurs during communication between the client and the server (whether using a web server or ClassFileServer), it is most likely because the necessary keys are not in the truststore (trust key database). See Terms and Definitions. For example, the ClassFileServer uses a keystore called testkeys containing the private key for localhost as needed during the SSL handshake. The testkeys keystore is included in the same samples/sockets/server directory as the ClassFileServer source. If the client cannot find a certificate for the corresponding public key of localhost in the truststore it consults, then an authentication error will occur. Be sure to use the samplecacerts truststore (which contains the public key and certificate of the localhost), as described in the next section.

    When running the sample programs that create a secure socket connection between a client and a server, you will need to make the appropriate certificates file (truststore) available. For both the client and the server programs, you should use the certificates file samplecacerts from the samples directory. Using this certificates file will allow the client to authenticate the server. The file contains all the common Certificate Authority (CA) certificates shipped with the JDK (in the cacerts file), plus a certificate for localhost needed by the client to authenticate localhost when communicating with the sample server ClassFileServer. The ClassFileServer uses a keystore containing the private key for localhost that corresponds to the public key in samplecacerts.

    To make the samplecacerts file available to both the client and the server, you can either copy it to the file <java-home>/lib/security/jssecacerts, rename it to cacerts, and use it to replace the <java-home>/lib/security/cacerts file, or add the following option to the command line when running the java command for both the client and the server:

    -Djavax.net.ssl.trustStore=path_to_samplecacerts_file
                            

    To know more about <java-home>, see Terms and Definitions.

    The password for the samplecacerts truststore is changeit. You can substitute your own certificates in the samples by using the keytool utility.

    If you use a browser, such as Mozilla Firefox or Microsoft Internet Explorer, to access the sample SSL server provided in the ClassFileServer example, then a dialog box may pop up with the message that it does not recognize the certificate. This is normal because the certificate used with the sample programs is self-signed and is for testing only. You can accept the certificate for the current session. After testing the SSL server, you should exit the browser, which deletes the test certificate from the browser's namespace.

    For client authentication, a separate duke certificate is available in the appropriate directories. The public key and certificate is also stored in the samplecacerts file.

    The SSLSocketClient.java program in JSSE Sample Code in the Java SE 8 documentation demonstrates how to create a client that uses an SSLSocket to send an HTTP request and to get a response from an HTTPS server. The output of this program is the HTML source for https://www.verisign.com/index.html.

    You must not be behind a firewall to run this program as provided. If you run it from behind a firewall, you will get an UnknownHostException because JSSE cannot find a path through your firewall to www.verisign.com. To create an equivalent client that can run from behind a firewall, set up proxy tunneling as illustrated in the sample program SSLSocketClientWithTunneling.

    The SSLSocketClientWithTunneling.java program in JSSE Sample Code in the Java SE 8 documentation illustrates how to do proxy tunneling to access a secure web server from behind a firewall. To run this program, you must set the following Java system properties to the appropriate values:

    java -Dhttps.proxyHost=webproxy
    -Dhttps.proxyPort=ProxyPortNumber
    SSLSocketClientWithTunneling
                                  

    Note:

    Proxy specifications with the -D options are optional. Replace webproxy with the name of your proxy host and ProxyPortNumber with the appropriate port number.

    The SSLSocketClientWithClientAuth.java program in JSSE Sample Code in the Java SE 8 documentation shows how to set up a key manager to do client authentication if required by a server. This program also assumes that the client is not outside a firewall. You can modify the program to connect from inside a firewall by following the example in SSLSocketClientWithTunneling.

    To run this program, you must specify three parameters: host name, port number, and requested file path. To mirror the previous examples, you can run this program without client authentication by setting the host to www.verisign.com, the port to 443, and the requested file path to https://www.verisign.com/. The output when using these parameters is the HTML for the website https://www.verisign.com/.

    To run SSLSocketClientWithClientAuth to do client authentication, you must access a server that requests client authentication. You can use the sample program ClassFileServer as this server. This is described in the following sections.

    The program referred to herein as ClassFileServer is made up of two files: ClassFileServer.java and ClassServer.java in JSSE Sample Code in the Java SE 8 documentation.

    To execute them, run ClassFileServer.class, which requires the following parameters:

  • port can be any available unused port number, for example, you can use the number 2001.
  • docroot indicates the directory on the server that contains the file you want to retrieve. For example, on Linux, you can use /home/userid/ (where userid refers to your particular UID), whereas on Windows, you can use c:\.
  • TLS is an optional parameter that indicates that the server is to use SSL or TLS.
  • true is an optional parameter that indicates that client authentication is required. This parameter is only consulted if the TLS parameter is

    The TLS and true parameters are optional. If you omit them, indicating that an ordinary (not TLS) file server should be used, without authentication, then nothing happens. This is because one side (the client) is trying to negotiate with TLS, while the other (the server) is not, so they cannot communicate.

    The server expects GET requests in the form GET /path_to_file. SSLSocketClientWithClientAuth.java and ClassFileServer in JSSE Sample Code in the Java SE 8 documentation to set up authenticated communication, where the client and server are authenticated to each other. You can run both sample programs on different machines connected to the same network, or you can run them both on one machine but from different terminal windows or command prompt windows. To set up both the client and the server, do the following:

  • Run the program ClassFileServer from one machine or terminal window. Running ClassFileServer.
  • Run the program SSLSocketClientWithClientAuth on another machine or terminal window. SSLSocketClientWithClientAuth requires the following parameters:
  • host is the host name of the machine that you are using to run ClassFileServer.
  • port is the same port that you specified for ClassFileServer.

    requestedfilepath indicates the path to the file that you want to retrieve from the server. You must give this parameter as /filepath. Forward slashes are required in the file path because it is used as part of a GET statement, which requires forward slashes regardless of what type of operating system you are running. The statement is formed as follows:

    "GET " + requestedfilepath + " HTTP/1.0"
                               

    Note:

    You can modify the other SSLClient* applications' GET commands to connect to a local machine running ClassFileServer.

    There are two primary APIs for accessing secure communications through JSSE. One way is through a socket-level API that can be used for arbitrary secure communications, as illustrated by the SSLSocketClient, SSLSocketClientWithTunneling, and SSLSocketClientWithClientAuth (with and without ClassFileServer) sample programs.

    A second, and often simpler, way is through the standard Java URL API. You can communicate securely with an SSL-enabled web server by using the HTTPS URL protocol or scheme using the java.net.URL class.

    Support for HTTPS URL schemes is implemented in many of the common browsers, which allows access to secured communications without requiring the socket-level API provided with JSSE.

    An example URL is https://www.verisign.com.

    The trust and key management for the HTTPS URL implementation is environment-specific. The JSSE implementation provides an HTTPS URL implementation. To use a different HTTPS protocol implementation, set the java.protocol.handler.pkgs. See How to Specify a java.lang.System Property to the package name. See the java.net.URL class documentation for details.

    The samples that you can download with JSSE include two sample programs that illustrate how to create an HTTPS connection. Both of these sample programs (URLReader.java and URLReaderWithOptions.java ) are in the samples/urls directory.

    The URLReader.java program in JSSE Sample Code in the Java SE 8 documentation illustrates using the URL class to access a secure site. The output of this program is the HTML source for https://www.verisign.com/. By default, the HTTPS protocol implementation included with JSSE is used. To use a different implementation, set the system property java.protocol.handler.pkgs value to be the name of the package containing the implementation.

    If you are running the sample code behind a firewall, then you must set the https.proxyHost and https.proxyPort system properties. For example, to use the proxy host "webproxy" on port 8080, you can use the following options for the java command:

    -Dhttps.proxyHost=webproxy
    -Dhttps.proxyPort=8080
                            

    Alternatively, you can set the system properties within the source code with the java.lang.System method setProperty(). For example, instead of using the command-line options, you can include the following lines in your program:

    System.setProperty("java.protocol.handler.pkgs", "com.ABC.myhttpsprotocol");
    System.setProperty("https.proxyHost", "webproxy");
    System.setProperty("https.proxyPort", "8080");
                            

    The URLReaderWithOptions.java program JSSE Sample Code in the Java SE 8 documentation is essentially the same as the URLReader.java program, except that it allows you to optionally input any or all of the following system properties as arguments to the program when you run

  • java.protocol.handler.pkgs
  • https.proxyHost
  • https.proxyPort
  • https.cipherSuites
  • To run URLReaderWithOptions, enter the following command:

    java URLReaderWithOptions [-h proxyhost -p proxyport] [-k protocolhandlerpkgs] [-c ciphersarray]
                               

    Note:

    Multiple protocol handlers can be included in the protocolhandlerpkgs argument as a list with items separated by vertical bars. Multiple SSL cipher suite names can be included in the ciphersarray argument as a list with items separated by commas. The possible cipher suite names are the same as those returned by the SSLSocket.getSupportedCipherSuites() method. The suite names are taken from the SSL and TLS protocol specifications.

    You need a protocolhandlerpkgs argument only if you want to use an HTTPS protocol handler implementation other than the default one provided by Oracle.

    If you are running the sample code behind a firewall, then you must include arguments for the proxy host and the proxy port. Additionally, you can include a list of cipher suites to enable.

    Here is an example of running URLReaderWithOptions and specifying the proxy host "webproxy" on port 8080:

    java URLReaderWithOptions -h webproxy -p 8080
                            

    The sample code in the samples/rmi directory illustrates how to create a secure Java Remote Method Invocation (RMI) connection. The sample code is basically a "Hello World" example modified to install and use a custom RMI socket factory.

    SSLEngine gives application developers flexibility when choosing I/O and compute strategies. Rather than tie the SSL/TLS implementation to a specific I/O abstraction (such as single-threaded SSLSockets), SSLEngine removes the I/O and compute constraints from the SSL/TLS implementation.

    As mentioned earlier, SSLEngine is an advanced API, and is not appropriate for casual use. Some introductory sample code is provided here that helps illustrate its use. The first demo removes most of the I/O and threading issues, and focuses on many of the SSLEngine methods. The second demo is a more realistic example showing how SSLEngine might be combined with Java NIO to create a rudimentary HTTP/HTTPS server.

    The SSLEngineSimpleDemo.java program in JSSE Sample Code in the Java SE 8 documentation is a very simple application that focuses on the operation of the SSLEngine while simplifying the I/O and threading issues. This application creates two SSLEngine objects that exchange SSL/TLS messages via common ByteBuffer objects. A single loop serially performs all of the engine operations and demonstrates how a secure connection is established (handshaking), how application data is transferred, and how the engine is closed.

    The SSLEngineResult provides a great deal of information about the current state of the SSLEngine. This example does not examine all of the states. It simplifies the I/O and threading issues to the point that this is not a good example for a production environment; nonetheless, it is useful to demonstrate the overall function of the SSLEngine.

    One of the most common problems people have in using JSSE is when the JSSE receives a certificate that is unknown to the mechanism that makes trust decisions. If an unknown certificate is received, the trust mechanism will throw an exception saying that the certificate is untrusted. Make sure that the correct trust store is being used, and that the JSSE is installed and configured correctly.

    If you are using the "localhost" or "duke" credentials, be sure that you have correctly specified the location of the samplecacerts file, otherwise your application will not work. (See Sample Certificates and Keys for more information.)

    The SSL debug mechanism can be used to investigate such trust problems. See the implementation documentation for more information about this subject.

    This section demonstrates how you can use the keytool utility to create a simple PKCS12 keystore suitable for use with JSSE.

    First you make a keyEntry (with public and private keys) in the keystore, and then you make a corresponding trustedCertEntry (public keys only) in a truststore. For client authentication, you follow a similar process for the client's certificates.

    Note:

    It is beyond the scope of this example to explain each step in detail. See the keytool command in Java Platform, Standard Edition Tools Reference for more information.

    User input is shown in bold.

    Create a new keystore and self-signed certificate with corresponding public and private keys.

    % keytool -genkeypair -alias duke -keyalg RSA -validity 7 -keystore keystore Enter keystore password: <password> What is your first and last name? [Unknown]: Duke What is the name of your organizational unit? [Unknown]: Java Software What is the name of your organization? [Unknown]: Oracle, Inc. What is the name of your City or Locality? [Unknown]: Palo Alto What is the name of your State or Province? [Unknown]: CA What is the two-letter country code for this unit? [Unknown]: US Is CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US correct? [no]: yes

    Examine the keystore. Notice that the entry type is PrivatekeyEntry, which means that this entry has a private key associated with it). % keytool -list -v -keystore keystore Enter keystore password: <password> Keystore type: PKCS12 Keystore provider: SUN Your keystore contains 1 entry Alias name: duke Creation date: Jul 25, 2016 Entry type: PrivateKeyEntry Certificate chain length: 1 Certificate[1]: Owner: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US Issuer: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US Serial number: 210cccfc Valid from: Mon Jul 25 10:33:27 IST 2016 until: Mon Aug 01 10:33:27 IST 2016 Certificate fingerprints: SHA1: 80:E5:8A:47:7E:4F:5A:70:83:97:DD:F4:DA:29:3D:15:6B:2A:45:1F SHA256: ED:3C:70:68:4E:86:35:9C:63:CC:B9:59:35:58:94:1F:7E:B8:B0:EE:D2: 4B:9D:80:31:67:8A:D4:B4:7A:B5:12 Signature algorithm name: SHA256withRSA Subject Public Key Algorithm: RSA (2048) Version: 3 Extensions: #1: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 7F C9 95 48 42 8D 68 91 BA 1E E6 5C 2C 6B FF 75 ...HB.h....\,k.u 0010: 5F 19 78 43 _.xC

    Export and examine the self-signed certificate.

    % keytool -export -alias duke -keystore keystore -rfc -file duke.cer Enter keystore password: <password> Certificate stored in file <duke.cer> % cat duke.cer -----BEGIN CERTIFICATE----- MIIDdzCCAl+gAwIBAgIEIQzM/DANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJV UzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzEVMBMGA1UEChMMT3Jh Y2xlLCBJbmMuMRYwFAYDVQQLEw1KYXZhIFNvZnR3YXJlMQ0wCwYDVQQDEwREdWtl MB4XDTE2MDcyNTA1MDMyN1oXDTE2MDgwMTA1MDMyN1owbDELMAkGA1UEBhMCVVMx CzAJBgNVBAgTAkNBMRIwEAYDVQQHEwlQYWxvIEFsdG8xFTATBgNVBAoTDE9yYWNs ZSwgSW5jLjEWMBQGA1UECxMNSmF2YSBTb2Z0d2FyZTENMAsGA1UEAxMERHVrZTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ7+Yeu6HDZgWwkGlG4iKH9w vGKrxXVR57FaFyheMevrgj1ovVnQVFhfdMvjPkjWmpqLg6rfTqU4bKbtoMWV6+Rn uQrCw2w9xNC93hX9PxRa20UKrSRDKnUSvi1wjlaxfj0KUKuMwbbY9S8x/naYGeTL lwbHiiMvkoFkP2kzhVgeqHjIwSz4HRN8vWHCwgIDFWX/ZlS+LbvB4TSZkS0ZcQUV vJWTocOd8RB90W3bkibWkWq166XYGE1Nq1L4WIhrVJwbav6ual69yJsEpVcshVkx E1WKzJg7dGb03to4agbReb6+aoCUwb2vNUudNWasSrxoEFArVFGD/ZkPT0esfqEC AwEAAaMhMB8wHQYDVR0OBBYEFH/JlUhCjWiRuh7mXCxr/3VfGXhDMA0GCSqGSIb3 DQEBCwUAA4IBAQAmcTm2ahsIJLayajsvm8yPzQsHA7kIwWfPPHCoHmNbynG67oHB fleaNvrgm/raTT3TrqQkg0525qI6Cqaoyy8JA2fAp3i+hmyoGHaIlo14bKazaiPS RCCqk0J8vwY3CY9nVal1XlHJMEcYV7X1sxKbuAKFoAJ29E/p6ie0JdHtQe31M7X9 FNLYzt8EpJYUtWo13B9Oufz/Guuex9PQ7aC93rbO32MxtnnCGMxQHlaHLLPygc/x cffGz5Xe5s+NEm78CY7thgN+drI7icBYmv4navsnr2OQaD3AfnJ4WYSQyyUUCPxN zuk+B0fbLn7PCCcQspmqfgzIpgbEM9M1/yav -----END CERTIFICATE-----

    Alternatively, you could generate a Certificate Signing Request (CSR) with the -certreq command and send that to a Certificate Authority (CA) for signing. See the section "Requesting a Signed Certificate from a CA" in the keytool command for an example. % keytool -import -alias dukecert -file duke.cer -keystore truststore Enter keystore password: <password> Re-enter new password: Owner: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US Issuer: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US Serial number: 210cccfc Valid from: Mon Jul 25 10:33:27 IST 2016 until: Mon Aug 01 10:33:27 IST 2016 Certificate fingerprints: SHA1: 80:E5:8A:47:7E:4F:5A:70:83:97:DD:F4:DA:29:3D:15:6B:2A:45:1F SHA256: ED:3C:70:68:4E:86:35:9C:63:CC:B9:59:35:58:94:1F:7E:B8:B0:EE:D2: 4B:9D:80:31:67:8A:D4:B4:7A:B5:12 Signature algorithm name: SHA256withRSA Subject Public Key Algorithm: RSA (2048) Version: 3 Extensions: #1: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 7F C9 95 48 42 8D 68 91 BA 1E E6 5C 2C 6B FF 75 ...HB.h....\,k.u 0010: 5F 19 78 43 _.xC Trust this certificate? [no]: yes Certificate was added to keystore

    Examine the truststore. Note that the entry type is trustedCertEntry, which means that a private key is not available for this entry. It also means that this file is not suitable as a keystore of the KeyManager. % keytool -list -v -keystore truststore Enter keystore password: <password> Keystore type: PKCS12 Keystore provider: SUN Your keystore contains 1 entry Alias name: dukecert Creation date: Jul 25, 2016 Entry type: trustedCertEntry Owner: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US Issuer: CN=Duke, OU=Java Software, O="Oracle, Inc.", L=Palo Alto, ST=CA, C=US Serial number: 210cccfc Valid from: Mon Jul 25 10:33:27 IST 2016 until: Mon Aug 01 10:33:27 IST 2016 Certificate fingerprints: SHA1: 80:E5:8A:47:7E:4F:5A:70:83:97:DD:F4:DA:29:3D:15:6B:2A:45:1F SHA256: ED:3C:70:68:4E:86:35:9C:63:CC:B9:59:35:58:94:1F:7E:B8:B0:EE:D2: 4B:9D:80:31:67:8A:D4:B4:7A:B5:12 Signature algorithm name: SHA256withRSA Subject Public Key Algorithm: RSA (2048) Version: 3 Extensions: #1: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: 7F C9 95 48 42 8D 68 91 BA 1E E6 5C 2C 6B FF 75 ...HB.h....\,k.u 0010: 5F 19 78 43 _.xC ******************************************* *******************************************

    Now run your applications with the appropriate keystores. Because this example assumes that the default X509KeyManager and X509TrustManager are used, you select the keystores using the system properties described in Customizing JSSE.

    % java -Djavax.net.ssl.keyStore=keystore -Djavax.net.ssl.keyStorePassword=password Server
    % java -Djavax.net.ssl.trustStore=truststore -Djavax.net.ssl.trustStorePassword=trustword Client

    Note:

    This example authenticated the server only. For client authentication, provide a similar keystore for the client's keys and an appropriate truststore for the server.

    Using the Server Name Indication (SNI) Extension

    These examples illustrate how you can use the Server Name Indication (SNI) Extension for client-side and server-side applications, and how it can be applied to a virtual infrastructure.

    For all examples in this section, to apply the parameters after you set them, call the setSSLParameters(SSLParameters) method on the corresponding SSLSocket, SSLEngine, or SSLServerSocket object.

    The following is a list of use cases that require understanding of the SNI extension for developing a client application:

    Case 1. The client wants to access www.example.com.

    Set the host name explicitly:

        SNIHostName serverName = new SNIHostName("www.example.com");
        sslParameters.setServerNames(Collections.singletonList(serverName)); 

    The client should always specify the host name explicitly.

    Case 2. The client does not want to use SNI because the server does not support it.

    Disable SNI with an empty server name list:

        sslParameters.setServerNames(Collections.emptyList());        
                                  

    Case 3. The client wants to access URL https://www.example.com.

    Oracle providers will set the host name in the SNI extension by default, but third-party providers may not support the default server name indication. To keep your application provider-independent, always set the host name explicitly.

    Case 4. The client wants to switch a socket from server mode to client mode.

    First switch the mode with the following method: sslSocket.setUseClientMode(true). Then reset the server name indication parameters on the socket.

    The following is a list of use cases that require understanding of the SNI extension for developing a server application:

    Case 1. The server wants to accept all server name indication types.

    If you do not have any code dealing with the SNI extension, then the server ignores all server name indication types.

    Case 2. The server wants to deny all server name indications of type host_name.

    Set an invalid server name pattern for host_name:

        SNIMatcher matcher = SNIHostName.createSNIMatcher("");
        Collection<SNIMatcher> matchers = new ArrayList<>(1);
        matchers.add(matcher);
        sslParameters.setSNIMatchers(matchers);        
    

    Another way is to create an SNIMatcher subclass with a matches() method that always returns false:

        class DenialSNIMatcher extends SNIMatcher {
            DenialSNIMatcher() {
                super(StandardConstants.SNI_HOST_NAME);
            @Override
            public boolean matches(SNIServerName serverName) {
                return false;
        SNIMatcher matcher = new DenialSNIMatcher();
        Collection<SNIMatcher> matchers = new ArrayList<>(1);
        matchers.add(matcher);
        sslParameters.setSNIMatchers(matchers);        
                                  

    Case 3. The server wants to accept connections to any host names in the example.com domain.

    Set the recognizable server name for host_name as a pattern that includes all *.example.com addresses:

        SNIMatcher matcher = SNIHostName.createSNIMatcher("(.*\\.)*example\\.com");
        Collection<SNIMatcher> matchers = new ArrayList<>(1);
        matchers.add(matcher);
        sslParameters.setSNIMatchers(matchers);
                                  

    Case 4. The server wants to switch a socket from client mode to server mode.

    First switch the mode with the following method: sslSocket.setUseClientMode(false). Then reset the server name indication parameters on the socket.

    Working with Virtual Infrastructures

    This section describes how to use the Server Name Indication (SNI) extension from within a virtual infrastructure. It illustrates how to create a parser for ClientHello messages from a socket, provides examples of virtual server dispatchers using SSLSocket and SSLEngine, describes what happens when the SNI extension is not available, and demonstrates how to create a failover SSLContext.

    Preparing the ClientHello Parser

    Applications must implement an API to parse the ClientHello messages from a socket. The following examples illustrate the SSLCapabilities and SSLExplorer classes that can perform these functions.

    SSLSocketClient.java encapsulates the TLS/DTLS security capabilities during handshaking (that is, the list of cipher suites to be accepted in an TLS/DTLS handshake, the record version, the hello version, and the server name indication). It can be retrieved by exploring the network data of an TLS/DTLS connection via the SSLExplorer.explore() method.

    SSLExplorer.java explores the initial ClientHello message from a TLS client, but it does not initiate handshaking or consume network data. The SSLExplorer.explore() method parses the ClientHello message, and retrieves the security parameters into SSLCapabilities. The method must be called before handshaking occurs on any TLS connections.

    Register the server name handler.

    At this step, the application may create different SSLContext objects for different server name indications, or link a certain server name indication to a specified virtual machine or distributed system.

    For example, if the server name is www.example.org, then the registered server name handler may be for a local virtual hosting web service. The local virtual hosting web service will use the specified SSLContext. If the server name is www.example.com, then the registered server name handler may be for a virtual machine hosting on 10.0.0.36. The handler may map this connection to the virtual machine.

    Create a ServerSocket and accept the new connection.

    ServerSocket serverSocket = new ServerSocket(serverPort);
    Socket socket = serverSocket.accept();
                                     

    Read and buffer bytes from the socket input stream, and then explore the buffered bytes.

    InputStream ins = socket.getInputStream();
    byte[] buffer = new byte[0xFF];
    int position = 0;
    SSLCapabilities capabilities = null;
    // Read the header of TLS record
    while (position < SSLExplorer.RECORD_HEADER_SIZE) {
        int count = SSLExplorer.RECORD_HEADER_SIZE - position;
        int n = ins.read(buffer, position, count);
        if (n < 0) {
            throw new Exception("unexpected end of stream!");
        position += n;
    // Get the required size to explore the SSL capabilities
    int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);
    if (buffer.length < recordLength) {
        buffer = Arrays.copyOf(buffer, recordLength);
    while (position < recordLength) {
        int count = recordLength - position;
        int n = ins.read(buffer, position, count);
        if (n < 0) {
            throw new Exception("unexpected end of stream!");
        position += n;
    // Explore
    capabilities = SSLExplorer.explore(buffer, 0, recordLength);
    if (capabilities != null) {
        System.out.println("Record version: " + capabilities.getRecordVersion());
        System.out.println("Hello version: " + capabilities.getHelloVersion());
                                     

    Get the requested server name from the explored capabilities.

    List<SNIServerName> serverNames = capabilities.getServerNames();
                                     

    Look for the registered server name handler for this server name indication.

    If the service of the host name is resident in a virtual machine or another distributed system, then the application must forward the connection to the destination. The application will need to read and write the raw internet data, rather then the SSL application from the socket stream.

    Socket destinationSocket = new Socket(serverName, 443);
    // Forward buffered bytes and network data from the current socket to the destinationSocket.
    

    If the service of the host name is resident in the same process, and the host name service can use the SSLSocket directly, then the application will need to set the SSLSocket instance to the server:

    // Get service context from registered handler
    // or create the context
    SSLContext serviceContext = ...
    SSLSocketFactory serviceSocketFac = serviceContext.getSSLSocketFactory();
    // wrap the buffered bytes
    ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, position);
    SSLSocket serviceSocket = (SSLSocket)serviceSocketFac.createSocket(socket, bais, true);
    // Now the service can use serviceSocket as usual.
                                     

    Register the server name handler.

    At this step, the application may create different SSLContext objects for different server name indications, or link a certain server name indication to a specified virtual machine or distributed system.

    For example, if the server name is www.example.org, then the registered server name handler may be for a local virtual hosting web service. The local virtual hosting web service will use the specified SSLContext. If the server name is www.example.com, then the registered server name handler may be for a virtual machine hosting on 10.0.0.36. The handler may map this connection to the virtual machine.

    Create a ServerSocket or ServerSocketChannel and accept the new connection.

    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.bind(...);
    SocketChannel socketChannel = serverSocketChannel.accept();
                                     

    Read and buffer bytes from the socket input stream, and then explore the buffered bytes.

    ByteBuffer buffer = ByteBuffer.allocate(0xFF);
    SSLCapabilities capabilities = null;
    while (true) {
        // ensure the capacity
        if (buffer.remaining() == 0) {
            ByteBuffer oldBuffer = buffer;
            buffer = ByteBuffer.allocate(buffer.capacity() + 0xFF);
            buffer.put(oldBuffer);
        int n = sc.read(buffer);
        if (n < 0) {
            throw new Exception("unexpected end of stream!");
        int position = buffer.position();
        buffer.flip();
        capabilities = explorer.explore(buffer);
        buffer.rewind();
        buffer.position(position);
        buffer.limit(buffer.capacity());
        if (capabilities != null) {
            System.out.println("Record version: " +
                capabilities.getRecordVersion());
            System.out.println("Hello version: " +
                capabilities.getHelloVersion());
            break;
    buffer.flip();  // reset the buffer position and limitation 
  • Get the requested server name from the explored capabilities.

    List<SNIServerName> serverNames = capabilities.getServerNames();
                                     

    Look for the registered server name handler for this server name indication.

    If the service of the host name is resident in a virtual machine or another distributed system, then the application must forward the connection to the destination. The application will need to read and write the raw internet data, rather then the SSL application from the socket stream.

    Socket destinationSocket = new Socket(serverName, 443);
    // Forward buffered bytes and network data from the current socket to the destinationSocket.
    

    If the service of the host name is resident in the same process, and the host name service can use the SSLEngine directly, then the application will simply feed the net data to the SSLEngine instance:

    // Get service context from registered handler
    // or create the context
    SSLContext serviceContext = ...
    SSLEngine serviceEngine = serviceContext.createSSLEngine();
    // Now the service can use the buffered bytes and other byte buffer as usual.
                               

    Failover SSLContext

    The SSLExplorer.explore() method does not check the validity of TLS/DTLS contents. If the record format does not comply with TLS/DTLS specification, or the explore() method is invoked after handshaking has started, then the method may throw an IOException and be unable to produce network data. In such cases, handle the exception thrown by SSLExplorer.explore() by using a failover SSLContext, which is not used to negotiate a TLS/DTLS connection, but to close the connection with the proper alert message. The following example illustrates a failover SSLContext. You can find an example of the DenialSNIMatcher class in Case 2 in Typical Server-Side Usage Examples.

    byte[] buffer = ...       // buffered network data
    boolean failed = true;    // SSLExplorer.explore() throws an exception
    SSLContext context = SSLContext.getInstance("TLS");
    // the failover SSLContext
    context.init(null, null, null);
    SSLSocketFactory sslsf = context.getSocketFactory();
    ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, position);
    SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);
    SNIMatcher matcher = new DenialSNIMatcher();
    Collection<SNIMatcher> matchers = new ArrayList<>(1);
    matchers.add(matcher);
    SSLParameters params = sslSocket.getSSLParameters();
    params.setSNIMatchers(matchers);    // no recognizable server name
    sslSocket.setSSLParameters(params);
    try {
        InputStream sslIS = sslSocket.getInputStream();
        sslIS.read();
    } catch (Exception e) {
        System.out.println("Server exception " + e);
    } finally {
        sslSocket.close();
                

    Provider Pluggability

    JSSE is fully pluggable and does not restrict the use of third-party JSSE providers in any way.

    JAXP Security Processing

    JAXP security processing instructs JAXP components such as parsers, transformers, and so on to behave in a secure fashion. Note that when a Security Manager is present, JAXP security processing is turned on automatically; otherwise, JAXP security processing is disabled by default.

    JAXP Security Processing Default Limitations

    The following table describes which XML-related factory classes are disabled and which processing limits are set if JAXP security processing is enabled.

    Table 8-10 Default Limitations Set by JAXP Security Processing on XML-Related Factory Classes

    XML-Related Factory Class Enabled? Processing Limits

    See Processing Limits in The Java Tutorials for more information about entityExpansionLimit, elementAttributeLimit, maxOccurLimit and other JAXP processing limits.

    The following sections describes the processing limits in this table in detail and how you can change them.

    Limit the the number of entity expansions by either setting the system property entityExpansionLimit or the parser property http://apache.org/xml/properties/entity-expansion-limit. Both properties accept java.lang.Integer values. The parser throws a fatal error once it has reached the entity expansion limit. By default, entityExpansionLimit is set to 64,000.

    The following command-line example sets the entity expansion limit to 10,000:

    java -DentityExpansionLimit=10000 MyApp 

    The following code example sets the entity expansion limit to 10,000:

        System.setProperty("entityExpansionLimit","10000");

    The following code example sets the parser property http://apache.org/xml/properties/entity-expansion-limit to 10,000:

        DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
        dfactory.setAttribute(
            "http://apache.org/xml/properties/entity-expansion-limit",
            new Integer("10000"));
        DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();

    Limiting Number of Element Attributes

    Limit the number of attributes in an element by either setting the system property elementAttributeLimit or by setting the parser property http://apache.org/xml/properties/elementAttributeLimit. Both properties accept Integer values. By default, elementAttributeLimit is set to 10,000. When the parser property http://apache.org/xml/properties/elementAttributeLimit is set, it overrides the system property. The parser throws a fatal error if the number of attributes in a element exceeds the limit.

    The following command-line example sets the element attribute limit to

    java -DelementAttributeLimit=20 MyApp

    The following code example sets the element attribute limit to 20:

    System.setProperty("elementAttributeLimit","20");

    The following code example sets the parser property http://apache.org/xml/properties/entity-expansion-limit to

        DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
        dfactory.setAttribute(
            "http://apache.org/xml/properties/elementAttributeLimit",
            new Integer(20));
        DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();

    Limit Number of Nodes Created by Constructs That Contain maxOccurs

    In constructs like xsd:sequence, the validating parser may use space (memory) proportional to the value of the maxOccurs occurrence indicator. This may cause the VM to run out of memory, or simply run for a very long time. To prevent potential attacks that exploit this behavior, enable secure processing on a factory as follows:

    factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);

    Note that for xsd:element and xsd:any, the validating parser uses a constant amount of space, which is independent of the value of the maxOccurs occurrence indicator.

    The default value of maxOccursLimit is 5,000. This system property limits the number of content model nodes that may be created when building a grammar for a W3C XML Schema that contains maxOccurs occurrence indicators with values other than "unbounded".

    By default, XPath and XSLT extension functions are disabled when JAXP secure processing is enabled. The following code enables JAXP secure processing and disables XPath and XSLT extension functions for XPathFactory:

        XPathFactory xpf = xPathFactory.newInstance();
        xpf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

    The following code enables JAXP secure processing and disables XSLT extension functions for TransformerFactory:

        TransformerFactory tf = TransformerFactory.newInstance();
        tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

    Security Issue Posed by Nested Entity Definitions

    While XML does not allow recursive entity definitions, it does permit nested entity definitions, which produces the potential for Denial of Service attacks on a server which accepts XML data from external sources. For example, a SOAP document like the following that has very deeply nested entity definitions can consume 100% of CPU time and large amounts of memory in entity expansions:

    <?xml version="1.0" encoding ="UTF-8"?>
    <!DOCTYPE foobar[
        <!ENTITY x100 "foobar">
        <!ENTITY  x99 "&x100;&x100;">
        <!ENTITY  x98 "&x99;&x99;">
        <!ENTITY   x2 "&x3;&x3;">
        <!ENTITY   x1 "&x2;&x2;">
    <SOAP-ENV:Envelope xmlns:SOAP-ENV=...>
        <SOAP-ENV:Body>
            <ns1:aaa xmlns:ns1="urn:aaa" SOAP-ENV:encodingStyle="...">
                <foobar xsi:type="xsd:string">&x1;</foobar>
            </ns1:aaa>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope> 

    You don't have worry about this issue if your system doesn't take in external XML data, but a system that does should turn on the secure processing feature and reset the limits as described in Limiting Entity Expansion and Limiting Number of Element Attributes.

    When you set the http://apache.org/xml/features/disallow-doctype-decl parser property to true, a fatal error is then thrown if the incoming XML document contains a DOCTYPE declaration. (The default value for this property is false.) This property is typically useful for SOAP based applications where a SOAP message must not contain a Document Type Declaration.

    The class XMLInputFactory includes the property javax.xml.stream.supportDTD that requests processors that do not support DTDs. StAX includes a similar property, XMLInputFactory.SUPPORT_DTD, that you can use to disable DTD processing:

        XMLInputFactory xif = XMLInputFactory.newInstance();
        xif.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);

    Resolving External Resources

    The following system properties restrict how XML parsers resolve external resources:

  • javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD
  • javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA
  • javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET
  • See JAXP 1.5 and New Properties in The Java Tutorials for more information about these properties.

    Turn off JAXP secure processing by calling the setFeature method on factories. The following code example turns off JAXP secure processing for the SAX parser:

        SAXParserFactory spf = SAXParserFactory.newInstance();
        spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,false);

    When you turn off JAXP secure processing for the DOM or SAX parser, you remove the default limiations specified by entityExpansionLimit, elementAttributeLimit, and maxOccurs.