changeset 30904:ec0224270f90

8043758: Datagram Transport Layer Security (DTLS) Reviewed-by: jnimeh, weijun, mullan, wetmore
author xuelei
date Tue, 02 Jun 2015 04:01:04 +0000
parents 0c7d705209c6
children bba6fefdd660
files jdk/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java jdk/src/java.base/share/classes/javax/net/ssl/SNIServerName.java jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java jdk/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java jdk/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java jdk/src/java.base/share/classes/javax/net/ssl/SSLParameters.java jdk/src/java.base/share/classes/javax/net/ssl/SSLSession.java jdk/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java jdk/src/java.base/share/classes/sun/security/ssl/AppInputStream.java jdk/src/java.base/share/classes/sun/security/ssl/AppOutputStream.java jdk/src/java.base/share/classes/sun/security/ssl/Authenticator.java jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java jdk/src/java.base/share/classes/sun/security/ssl/Ciphertext.java jdk/src/java.base/share/classes/sun/security/ssl/ClientAuthType.java jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java jdk/src/java.base/share/classes/sun/security/ssl/Debug.java jdk/src/java.base/share/classes/sun/security/ssl/EngineArgs.java jdk/src/java.base/share/classes/sun/security/ssl/EngineInputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/EngineOutputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/EngineWriter.java jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java jdk/src/java.base/share/classes/sun/security/ssl/HandshakeStateManager.java jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java jdk/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/MAC.java jdk/src/java.base/share/classes/sun/security/ssl/MaxFragmentLengthExtension.java jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java jdk/src/java.base/share/classes/sun/security/ssl/ProtocolList.java jdk/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java jdk/src/java.base/share/classes/sun/security/ssl/Record.java jdk/src/java.base/share/classes/sun/security/ssl/RecordType.java jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/SSLRecord.java jdk/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java jdk/src/java.base/share/classes/sun/security/ssl/SunJSSE.java jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java jdk/src/java.base/share/conf/security/java.security jdk/test/javax/net/ssl/DTLS/CipherSuite.java jdk/test/javax/net/ssl/DTLS/ClientAuth.java jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java jdk/test/javax/net/ssl/DTLS/InvalidCookie.java jdk/test/javax/net/ssl/DTLS/InvalidRecords.java jdk/test/javax/net/ssl/DTLS/NoMacInitialClientHello.java jdk/test/javax/net/ssl/DTLS/Reordered.java jdk/test/javax/net/ssl/DTLS/Retransmission.java jdk/test/javax/net/ssl/DTLS/WeakCipherSuite.java jdk/test/javax/net/ssl/SSLEngine/CheckStatus.java jdk/test/javax/net/ssl/SSLEngine/LargeBufs.java jdk/test/javax/net/ssl/TLS/CipherTestUtils.java jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java jdk/test/sun/security/ssl/AppInputStream/ReadHandshake.java jdk/test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java
diffstat 76 files changed, 11202 insertions(+), 4962 deletions(-) [+]
line wrap: on
line diff
--- a/jdk/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 import java.util.List;
 
 /**
- * Extends the <code>SSLSession</code> interface to support additional
+ * Extends the {@code SSLSession} interface to support additional
  * session attributes.
  *
  * @since 1.7
@@ -39,8 +39,8 @@
      * is willing to use.
      * <p>
      * Note: this method is used to indicate to the peer which signature
-     * algorithms may be used for digital signatures in TLS 1.2. It is
-     * not meaningful for TLS versions prior to 1.2.
+     * algorithms may be used for digital signatures in TLS/DTLS 1.2. It is
+     * not meaningful for TLS/DTLS versions prior to 1.2.
      * <p>
      * The signature algorithm name must be a standard Java Security
      * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
@@ -52,7 +52,7 @@
      * Note: the local supported signature algorithms should conform to
      * the algorithm constraints specified by
      * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
-     * method in <code>SSLParameters</code>.
+     * method in {@code SSLParameters}.
      *
      * @return An array of supported signature algorithms, in descending
      *     order of preference.  The return value is an empty array if
@@ -67,8 +67,8 @@
      * able to use.
      * <p>
      * Note: this method is used to indicate to the local side which signature
-     * algorithms may be used for digital signatures in TLS 1.2. It is
-     * not meaningful for TLS versions prior to 1.2.
+     * algorithms may be used for digital signatures in TLS/DTLS 1.2. It is
+     * not meaningful for TLS/DTLS versions prior to 1.2.
      * <p>
      * The signature algorithm name must be a standard Java Security
      * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SNIServerName.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SNIServerName.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
  * Instances of this class represent a server name in a Server Name
  * Indication (SNI) extension.
  * <P>
- * The SNI extension is a feature that extends the SSL/TLS protocols to
+ * The SNI extension is a feature that extends the SSL/TLS/DTLS protocols to
  * indicate what server name the client is attempting to connect to during
  * handshaking.  See section 3, "Server Name Indication", of <A
  * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>.
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,12 +32,12 @@
 /**
  * Instances of this class represent a secure socket protocol
  * implementation which acts as a factory for secure socket
- * factories or <code>SSLEngine</code>s. This class is initialized
+ * factories or {@code SSLEngine}s. This class is initialized
  * with an optional set of key and trust managers and source of
  * secure random bytes.
  *
  * <p> Every implementation of the Java platform is required to support the
- * following standard <code>SSLContext</code> protocol:
+ * following standard {@code SSLContext} protocol:
  * <ul>
  * <li><tt>TLSv1</tt></li>
  * </ul>
@@ -79,7 +79,7 @@
      * <p>If a default context was set using the {@link #setDefault
      * SSLContext.setDefault()} method, it is returned. Otherwise, the first
      * call of this method triggers the call
-     * <code>SSLContext.getInstance("Default")</code>.
+     * {@code SSLContext.getInstance("Default")}.
      * If successful, that object is made the default SSL context and returned.
      *
      * <p>The default context is immediately
@@ -106,8 +106,8 @@
      * @param context the SSLContext
      * @throws  NullPointerException if context is null
      * @throws  SecurityException if a security manager exists and its
-     *          <code>checkPermission</code> method does not allow
-     *          <code>SSLPermission("setDefaultSSLContext")</code>
+     *          {@code checkPermission} method does not allow
+     *          {@code SSLPermission("setDefaultSSLContext")}
      * @since 1.6
      */
     public static synchronized void setDefault(SSLContext context) {
@@ -122,7 +122,7 @@
     }
 
     /**
-     * Returns a <code>SSLContext</code> object that implements the
+     * Returns a {@code SSLContext} object that implements the
      * specified secure socket protocol.
      *
      * <p> This method traverses the list of registered security Providers,
@@ -141,7 +141,7 @@
      *          Documentation</a>
      *          for information about standard protocol names.
      *
-     * @return the new <code>SSLContext</code> object.
+     * @return the new {@code SSLContext} object.
      *
      * @exception NoSuchAlgorithmException if no Provider supports a
      *          SSLContextSpi implementation for the
@@ -159,7 +159,7 @@
     }
 
     /**
-     * Returns a <code>SSLContext</code> object that implements the
+     * Returns a {@code SSLContext} object that implements the
      * specified secure socket protocol.
      *
      * <p> A new SSLContext object encapsulating the
@@ -179,7 +179,7 @@
      *
      * @param provider the name of the provider.
      *
-     * @return the new <code>SSLContext</code> object.
+     * @return the new {@code SSLContext} object.
      *
      * @throws NoSuchAlgorithmException if a SSLContextSpi
      *          implementation for the specified protocol is not
@@ -202,7 +202,7 @@
     }
 
     /**
-     * Returns a <code>SSLContext</code> object that implements the
+     * Returns a {@code SSLContext} object that implements the
      * specified secure socket protocol.
      *
      * <p> A new SSLContext object encapsulating the
@@ -219,7 +219,7 @@
      *
      * @param provider an instance of the provider.
      *
-     * @return the new <code>SSLContext</code> object.
+     * @return the new {@code SSLContext} object.
      *
      * @throws NoSuchAlgorithmException if a SSLContextSpi
      *          implementation for the specified protocol is not available
@@ -239,22 +239,22 @@
     }
 
     /**
-     * Returns the protocol name of this <code>SSLContext</code> object.
+     * Returns the protocol name of this {@code SSLContext} object.
      *
      * <p>This is the same name that was specified in one of the
-     * <code>getInstance</code> calls that created this
-     * <code>SSLContext</code> object.
+     * {@code getInstance} calls that created this
+     * {@code SSLContext} object.
      *
-     * @return the protocol name of this <code>SSLContext</code> object.
+     * @return the protocol name of this {@code SSLContext} object.
      */
     public final String getProtocol() {
         return this.protocol;
     }
 
     /**
-     * Returns the provider of this <code>SSLContext</code> object.
+     * Returns the provider of this {@code SSLContext} object.
      *
-     * @return the provider of this <code>SSLContext</code> object
+     * @return the provider of this {@code SSLContext} object
      */
     public final Provider getProvider() {
         return this.provider;
@@ -283,31 +283,35 @@
     }
 
     /**
-     * Returns a <code>SocketFactory</code> object for this
+     * Returns a {@code SocketFactory} object for this
      * context.
      *
-     * @return the <code>SocketFactory</code> object
+     * @return the {@code SocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *         initialization and the {@code init()} has not been called
      */
     public final SSLSocketFactory getSocketFactory() {
         return contextSpi.engineGetSocketFactory();
     }
 
     /**
-     * Returns a <code>ServerSocketFactory</code> object for
+     * Returns a {@code ServerSocketFactory} object for
      * this context.
      *
-     * @return the <code>ServerSocketFactory</code> object
+     * @return the {@code ServerSocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *         initialization and the {@code init()} has not been called
      */
     public final SSLServerSocketFactory getServerSocketFactory() {
         return contextSpi.engineGetServerSocketFactory();
     }
 
     /**
-     * Creates a new <code>SSLEngine</code> using this context.
+     * Creates a new {@code SSLEngine} using this context.
      * <P>
      * Applications using this factory method are providing no hints
      * for an internal session reuse strategy. If hints are desired,
@@ -317,11 +321,11 @@
      * Some cipher suites (such as Kerberos) require remote hostname
      * information, in which case this factory method should not be used.
      *
-     * @return  the <code>SSLEngine</code> object
+     * @return  the {@code SSLEngine} object
      * @throws  UnsupportedOperationException if the underlying provider
      *          does not implement the operation.
      * @throws  IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *          initialization and the {@code init()} has not been called
      * @since   1.5
      */
     public final SSLEngine createSSLEngine() {
@@ -338,7 +342,7 @@
     }
 
     /**
-     * Creates a new <code>SSLEngine</code> using this context using
+     * Creates a new {@code SSLEngine} using this context using
      * advisory peer information.
      * <P>
      * Applications using this factory method are providing hints
@@ -349,11 +353,11 @@
      *
      * @param   peerHost the non-authoritative name of the host
      * @param   peerPort the non-authoritative port
-     * @return  the new <code>SSLEngine</code> object
+     * @return  the new {@code SSLEngine} object
      * @throws  UnsupportedOperationException if the underlying provider
      *          does not implement the operation.
      * @throws  IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *          initialization and the {@code init()} has not been called
      * @since   1.5
      */
     public final SSLEngine createSSLEngine(String peerHost, int peerPort) {
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 
 /**
  * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
- * for the <code>SSLContext</code> class.
+ * for the {@code SSLContext} class.
  *
  * <p> All the abstract methods in this class must be implemented by each
  * cryptographic service provider who wishes to supply the implementation
@@ -52,31 +52,35 @@
         SecureRandom sr) throws KeyManagementException;
 
     /**
-     * Returns a <code>SocketFactory</code> object for this
+     * Returns a {@code SocketFactory} object for this
      * context.
      *
-     * @return the <code>SocketFactory</code> object
+     * @return the {@code SocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      * @see javax.net.ssl.SSLContext#getSocketFactory()
      */
     protected abstract SSLSocketFactory engineGetSocketFactory();
 
     /**
-     * Returns a <code>ServerSocketFactory</code> object for
+     * Returns a {@code ServerSocketFactory} object for
      * this context.
      *
-     * @return the <code>ServerSocketFactory</code> object
+     * @return the {@code ServerSocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      * @see javax.net.ssl.SSLContext#getServerSocketFactory()
      */
     protected abstract SSLServerSocketFactory engineGetServerSocketFactory();
 
     /**
-     * Creates a new <code>SSLEngine</code> using this context.
+     * Creates a new {@code SSLEngine} using this context.
      * <P>
      * Applications using this factory method are providing no hints
      * for an internal session reuse strategy. If hints are desired,
@@ -86,9 +90,9 @@
      * Some cipher suites (such as Kerberos) require remote hostname
      * information, in which case this factory method should not be used.
      *
-     * @return  the <code>SSLEngine</code> Object
+     * @return  the {@code SSLEngine} Object
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      *
      * @see     SSLContext#createSSLEngine()
@@ -98,7 +102,7 @@
     protected abstract SSLEngine engineCreateSSLEngine();
 
     /**
-     * Creates a <code>SSLEngine</code> using this context.
+     * Creates a {@code SSLEngine} using this context.
      * <P>
      * Applications using this factory method are providing hints
      * for an internal session reuse strategy.
@@ -108,9 +112,9 @@
      *
      * @param host the non-authoritative name of the host
      * @param port the non-authoritative port
-     * @return  the <code>SSLEngine</code> Object
+     * @return  the {@code SSLEngine} Object
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      *
      * @see     SSLContext#createSSLEngine(String, int)
@@ -120,19 +124,19 @@
     protected abstract SSLEngine engineCreateSSLEngine(String host, int port);
 
     /**
-     * Returns a server <code>SSLSessionContext</code> object for
+     * Returns a server {@code SSLSessionContext} object for
      * this context.
      *
-     * @return the <code>SSLSessionContext</code> object
+     * @return the {@code SSLSessionContext} object
      * @see javax.net.ssl.SSLContext#getServerSessionContext()
      */
     protected abstract SSLSessionContext engineGetServerSessionContext();
 
     /**
-     * Returns a client <code>SSLSessionContext</code> object for
+     * Returns a client {@code SSLSessionContext} object for
      * this context.
      *
-     * @return the <code>SSLSessionContext</code> object
+     * @return the {@code SSLSessionContext} object
      * @see javax.net.ssl.SSLContext#getClientSessionContext()
      */
     protected abstract SSLSessionContext engineGetClientSessionContext();
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,15 +37,15 @@
  * <P>
  * The secure communications modes include: <UL>
  *
- *      <LI> <em>Integrity Protection</em>.  SSL/TLS protects against
+ *      <LI> <em>Integrity Protection</em>.  SSL/TLS/DTLS protects against
  *      modification of messages by an active wiretapper.
  *
- *      <LI> <em>Authentication</em>.  In most modes, SSL/TLS provides
+ *      <LI> <em>Authentication</em>.  In most modes, SSL/TLS/DTLS provides
  *      peer authentication.  Servers are usually authenticated, and
  *      clients may be authenticated as requested by servers.
  *
  *      <LI> <em>Confidentiality (Privacy Protection)</em>.  In most
- *      modes, SSL/TLS encrypts data being sent between client and
+ *      modes, SSL/TLS/DTLS encrypts data being sent between client and
  *      server.  This protects the confidentiality of data, so that
  *      passive wiretappers won't see sensitive data such as financial
  *      information or personal information of many kinds.
@@ -65,19 +65,19 @@
  * handshaking has completed, you can access session attributes by
  * using the {@link #getSession()} method.
  * <P>
- * The <code>SSLSocket</code> class provides much of the same security
+ * The {@code SSLSocket} class provides much of the same security
  * functionality, but all of the inbound and outbound data is
  * automatically transported using the underlying {@link
  * java.net.Socket Socket}, which by design uses a blocking model.
  * While this is appropriate for many applications, this model does not
  * provide the scalability required by large servers.
  * <P>
- * The primary distinction of an <code>SSLEngine</code> is that it
+ * The primary distinction of an {@code SSLEngine} is that it
  * operates on inbound and outbound byte streams, independent of the
  * transport mechanism.  It is the responsibility of the
- * <code>SSLEngine</code> user to arrange for reliable I/O transport to
- * the peer.  By separating the SSL/TLS abstraction from the I/O
- * transport mechanism, the <code>SSLEngine</code> can be used for a
+ * {@code SSLEngine} user to arrange for reliable I/O transport to
+ * the peer.  By separating the SSL/TLS/DTLS abstraction from the I/O
+ * transport mechanism, the {@code SSLEngine} can be used for a
  * wide variety of I/O types, such as {@link
  * java.nio.channels.spi.AbstractSelectableChannel#configureBlocking(boolean)
  * non-blocking I/O (polling)}, {@link java.nio.channels.Selector
@@ -87,7 +87,7 @@
  * HREF="http://www.jcp.org/en/jsr/detail?id=203"> future asynchronous
  * I/O models </A>, and so on.
  * <P>
- * At a high level, the <code>SSLEngine</code> appears thus:
+ * At a high level, the {@code SSLEngine} appears thus:
  *
  * <pre>
  *                   app data
@@ -115,18 +115,18 @@
  * mechanism.  Inbound data is data which has been received from the
  * peer, and outbound data is destined for the peer.
  * <P>
- * (In the context of an <code>SSLEngine</code>, the term "handshake
+ * (In the context of an {@code SSLEngine}, the term "handshake
  * data" is taken to mean any data exchanged to establish and control a
- * secure connection.  Handshake data includes the SSL/TLS messages
+ * secure connection.  Handshake data includes the SSL/TLS/DTLS messages
  * "alert", "change_cipher_spec," and "handshake.")
  * <P>
- * There are five distinct phases to an <code>SSLEngine</code>.
+ * There are five distinct phases to an {@code SSLEngine}.
  *
  * <OL>
- *     <li> Creation - The <code>SSLEngine</code> has been created and
+ *     <li> Creation - The {@code SSLEngine} has been created and
  *     initialized, but has not yet been used.  During this phase, an
- *     application may set any <code>SSLEngine</code>-specific settings
- *     (enabled cipher suites, whether the <code>SSLEngine</code> should
+ *     application may set any {@code SSLEngine}-specific settings
+ *     (enabled cipher suites, whether the {@code SSLEngine} should
  *     handshake in client or server mode, and so on).  Once
  *     handshaking has begun, though, any new settings (except
  *     client/server mode, see below) will be used for
@@ -139,7 +139,7 @@
  *
  *     <li> Application Data - Once the communication parameters have
  *     been established and the handshake is complete, application data
- *     may flow through the <code>SSLEngine</code>.  Outbound
+ *     may flow through the {@code SSLEngine}.  Outbound
  *     application messages are encrypted and integrity protected,
  *     and inbound messages reverse the process.
  *
@@ -147,50 +147,50 @@
  *     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 SSL/TLS communication parameters such as the list of
+ *     reset the SSL/TLS/DTLS communication parameters such as the list of
  *     enabled ciphersuites and whether to use client authentication,
  *     but can not change between client/server modes.  As before, once
- *     handshaking has begun, any new <code>SSLEngine</code>
+ *     handshaking has begun, any new {@code SSLEngine}
  *     configuration settings will not be used until the next
  *     handshake.
  *
  *     <li>  Closure - When the connection is no longer needed, the
- *     application should close the <code>SSLEngine</code> and should
+ *     application should close the {@code 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 <code>SSLEngine</code> must
+ *     closed, it is not reusable:  a new {@code SSLEngine} must
  *     be created.
  * </OL>
- * An <code>SSLEngine</code> is created by calling {@link
+ * An {@code SSLEngine} is created by calling {@link
  * SSLContext#createSSLEngine()} from an initialized
- * <code>SSLContext</code>.  Any configuration
+ * {@code SSLContext}.  Any configuration
  * parameters should be set before making the first call to
- * <code>wrap()</code>, <code>unwrap()</code>, or
- * <code>beginHandshake()</code>.  These methods all trigger the
+ * {@code wrap()}, {@code unwrap()}, or
+ * {@code beginHandshake()}.  These methods all trigger the
  * initial handshake.
  * <P>
  * Data moves through the engine by calling {@link #wrap(ByteBuffer,
  * ByteBuffer) wrap()} or {@link #unwrap(ByteBuffer, ByteBuffer)
  * unwrap()} on outbound or inbound data, respectively.  Depending on
- * the state of the <code>SSLEngine</code>, a <code>wrap()</code> call
+ * the state of the {@code SSLEngine}, a {@code wrap()} call
  * may consume application data from the source buffer and may produce
  * network data in the destination buffer.  The outbound data
  * may contain application and/or handshake data.  A call to
- * <code>unwrap()</code> will examine the source buffer and may
+ * {@code unwrap()} will examine the source buffer and may
  * advance the handshake if the data is handshaking information, or
  * may place application data in the destination buffer if the data
- * is application.  The state of the underlying SSL/TLS algorithm
+ * is application.  The state of the underlying SSL/TLS/DTLS algorithm
  * will determine when data is consumed and produced.
  * <P>
- * Calls to <code>wrap()</code> and <code>unwrap()</code> return an
- * <code>SSLEngineResult</code> which indicates the status of the
+ * Calls to {@code wrap()} and {@code unwrap()} return an
+ * {@code SSLEngineResult} which indicates the status of the
  * operation, and (optionally) how to interact with the engine to make
  * progress.
  * <P>
- * The <code>SSLEngine</code> produces/consumes complete SSL/TLS
+ * The {@code SSLEngine} produces/consumes complete SSL/TLS/DTLS
  * packets only, and does not store application data internally between
- * calls to <code>wrap()/unwrap()</code>.  Thus input and output
- * <code>ByteBuffer</code>s must be sized appropriately to hold the
+ * calls to {@code wrap()/unwrap()}.  Thus input and output
+ * {@code ByteBuffer}s must be sized appropriately to hold the
  * maximum record that can be produced.  Calls to {@link
  * SSLSession#getPacketBufferSize()} and {@link
  * SSLSession#getApplicationBufferSize()} should be used to determine
@@ -200,12 +200,12 @@
  * must determine (via {@link SSLEngineResult}) and correct the
  * problem, and then try the call again.
  * <P>
- * For example, <code>unwrap()</code> will return a {@link
+ * For example, {@code unwrap()} will return a {@link
  * SSLEngineResult.Status#BUFFER_OVERFLOW} result if the engine
  * determines that there is not enough destination buffer space available.
  * Applications should call {@link SSLSession#getApplicationBufferSize()}
  * and compare that value with the space available in the destination buffer,
- * enlarging the buffer if necessary.  Similarly, if <code>unwrap()</code>
+ * enlarging the buffer if necessary.  Similarly, if {@code unwrap()}
  * were to return a {@link SSLEngineResult.Status#BUFFER_UNDERFLOW}, the
  * application should call {@link SSLSession#getPacketBufferSize()} to ensure
  * that the source buffer has enough room to hold a record (enlarging if
@@ -241,8 +241,8 @@
  * }</pre>
  *
  * <P>
- * Unlike <code>SSLSocket</code>, all methods of SSLEngine are
- * non-blocking.  <code>SSLEngine</code> implementations may
+ * Unlike {@code SSLSocket}, all methods of SSLEngine are
+ * non-blocking.  {@code SSLEngine} implementations may
  * require the results of tasks that may take an extended period of
  * time to complete, or may even block.  For example, a TrustManager
  * may need to connect to a remote certificate validation service,
@@ -252,8 +252,8 @@
  * seemingly blocking.
  * <P>
  * For any operation which may potentially block, the
- * <code>SSLEngine</code> will create a {@link java.lang.Runnable}
- * delegated task.  When <code>SSLEngineResult</code> indicates that a
+ * {@code SSLEngine} will create a {@link java.lang.Runnable}
+ * delegated task.  When {@code SSLEngineResult} indicates that a
  * delegated task result is needed, the application must call {@link
  * #getDelegatedTask()} to obtain an outstanding delegated task and
  * call its {@link java.lang.Runnable#run() run()} method (possibly using
@@ -262,16 +262,16 @@
  * exist, and try the original operation again.
  * <P>
  * At the end of a communication session, applications should properly
- * close the SSL/TLS link.  The SSL/TLS protocols have closure handshake
- * messages, and these messages should be communicated to the peer
- * before releasing the <code>SSLEngine</code> and closing the
+ * close the SSL/TLS/DTLS link.  The SSL/TLS/DTLS protocols have closure
+ * handshake messages, and these messages should be communicated to the
+ * peer before releasing the {@code SSLEngine} and closing the
  * underlying transport mechanism.  A close can be initiated by one of:
  * an SSLException, an inbound closure handshake message, or one of the
  * close methods.  In all cases, closure handshake messages are
- * generated by the engine, and <code>wrap()</code> should be repeatedly
- * called until the resulting <code>SSLEngineResult</code>'s status
+ * generated by the engine, and {@code wrap()} should be repeatedly
+ * called until the resulting {@code SSLEngineResult}'s status
  * returns "CLOSED", or {@link #isOutboundDone()} returns true.  All
- * data obtained from the <code>wrap()</code> method should be sent to the
+ * data obtained from the {@code wrap()} method should be sent to the
  * peer.
  * <P>
  * {@link #closeOutbound()} is used to signal the engine that the
@@ -279,12 +279,12 @@
  * <P>
  * A peer will signal its intent to close by sending its own closure
  * handshake message.  After this message has been received and
- * processed by the local <code>SSLEngine</code>'s <code>unwrap()</code>
+ * processed by the local {@code SSLEngine}'s {@code unwrap()}
  * call, the application can detect the close by calling
- * <code>unwrap()</code> and looking for a <code>SSLEngineResult</code>
+ * {@code unwrap()} and looking for a {@code SSLEngineResult}
  * with status "CLOSED", or if {@link #isInboundDone()} returns true.
  * If for some reason the peer closes the communication link without
- * sending the proper SSL/TLS closure message, the application can
+ * sending the proper SSL/TLS/DTLS closure message, the application can
  * detect the end-of-stream and can signal the engine via {@link
  * #closeInbound()} that there will no more inbound messages to
  * process.  Some applications might choose to require orderly shutdown
@@ -315,16 +315,16 @@
  * and/or non-private (unencrypted) communications will such a
  * cipher suite be selected.
  * <P>
- * Each SSL/TLS connection must have one client and one server, thus
+ * Each SSL/TLS/DTLS connection must have one client and one server, thus
  * each endpoint must decide which role to assume.  This choice determines
  * who begins the handshaking process as well as which type of messages
  * should be sent by each party.  The method {@link
  * #setUseClientMode(boolean)} configures the mode.  Once the initial
- * handshaking has started, an <code>SSLEngine</code> can not switch
+ * handshaking has started, an {@code SSLEngine} can not switch
  * between client and server modes, even when performing renegotiations.
  * <P>
  * Applications might choose to process delegated tasks in different
- * threads.  When an <code>SSLEngine</code>
+ * threads.  When an {@code SSLEngine}
  * is created, the current {@link java.security.AccessControlContext}
  * is saved.  All future delegated tasks will be processed using this
  * context:  that is, all access control decisions will be made using the
@@ -336,10 +336,10 @@
  * There are two concurrency issues to be aware of:
  *
  * <OL>
- *      <li>The <code>wrap()</code> and <code>unwrap()</code> methods
+ *      <li>The {@code wrap()} and {@code unwrap()} methods
  *      may execute concurrently of each other.
  *
- *      <li> The SSL/TLS protocols employ ordered packets.
+ *      <li> The SSL/TLS/DTLS protocols employ ordered packets.
  *      Applications must take care to ensure that generated packets
  *      are delivered in sequence.  If packets arrive
  *      out-of-order, unexpected or fatal results may occur.
@@ -354,7 +354,7 @@
  *      </pre>
  *
  *      As a corollary, two threads must not attempt to call the same method
- *      (either <code>wrap()</code> or <code>unwrap()</code>) concurrently,
+ *      (either {@code wrap()} or {@code unwrap()}) concurrently,
  *      because there is no way to guarantee the eventual packet ordering.
  * </OL>
  *
@@ -374,7 +374,7 @@
     private int peerPort = -1;
 
     /**
-     * Constructor for an <code>SSLEngine</code> providing no hints
+     * Constructor for an {@code SSLEngine} providing no hints
      * for an internal session reuse strategy.
      *
      * @see     SSLContext#createSSLEngine()
@@ -384,10 +384,10 @@
     }
 
     /**
-     * Constructor for an <code>SSLEngine</code>.
+     * Constructor for an {@code SSLEngine}.
      * <P>
-     * <code>SSLEngine</code> implementations may use the
-     * <code>peerHost</code> and <code>peerPort</code> parameters as hints
+     * {@code SSLEngine} implementations may use the
+     * {@code peerHost} and {@code peerPort} parameters as hints
      * for their internal session reuse strategy.
      * <P>
      * Some cipher suites (such as Kerberos) require remote hostname
@@ -395,7 +395,7 @@
      * constructor to use Kerberos.
      * <P>
      * The parameters are not authenticated by the
-     * <code>SSLEngine</code>.
+     * {@code SSLEngine}.
      *
      * @param   peerHost the name of the peer host
      * @param   peerPort the port number of the peer
@@ -435,7 +435,7 @@
 
     /**
      * Attempts to encode a buffer of plaintext application data into
-     * SSL/TLS network data.
+     * SSL/TLS/DTLS network data.
      * <P>
      * An invocation of this method behaves in exactly the same manner
      * as the invocation:
@@ -445,20 +445,20 @@
      * </pre></blockquote>
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing outbound application data
+     *          a {@code ByteBuffer} containing outbound application data
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold outbound network data
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold outbound network data
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dst</code>
+     *          if either {@code src} or {@code dst}
      *          is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -471,7 +471,7 @@
 
     /**
      * Attempts to encode plaintext bytes from a sequence of data
-     * buffers into SSL/TLS network data.
+     * buffers into SSL/TLS/DTLS network data.
      * <P>
      * An invocation of this method behaves in exactly the same manner
      * as the invocation:
@@ -481,22 +481,22 @@
      * </pre></blockquote>
      *
      * @param   srcs
-     *          an array of <code>ByteBuffers</code> containing the
+     *          an array of {@code ByteBuffers} containing the
      *          outbound application data
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold outbound network data
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold outbound network data
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>srcs</code> or <code>dst</code>
-     *          is null, or if any element in <code>srcs</code> is null.
+     *          if either {@code srcs} or {@code dst}
+     *          is null, or if any element in {@code srcs} is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
      * @see     #wrap(ByteBuffer [], int, int, ByteBuffer)
@@ -512,7 +512,7 @@
 
     /**
      * Attempts to encode plaintext bytes from a subsequence of data
-     * buffers into SSL/TLS network data.  This <i>"gathering"</i>
+     * buffers into SSL/TLS/DTLS network data.  This <i>"gathering"</i>
      * operation encodes, in a single invocation, a sequence of bytes
      * from one or more of a given sequence of buffers.  Gathering
      * wraps are often useful when implementing network protocols or
@@ -535,49 +535,49 @@
      * it was generated.  The application must properly synchronize
      * multiple calls to this method.
      * <P>
-     * If this <code>SSLEngine</code> has not yet started its initial
+     * If this {@code SSLEngine} has not yet started its initial
      * handshake, this method will automatically start the handshake.
      * <P>
-     * This method will attempt to produce SSL/TLS records, and will
+     * This method will attempt to produce SSL/TLS/DTLS records, and will
      * consume as much source data as possible, but will never consume
      * more than the sum of the bytes remaining in each buffer.  Each
-     * <code>ByteBuffer</code>'s position is updated to reflect the
+     * {@code ByteBuffer}'s position is updated to reflect the
      * amount of data consumed or produced.  The limits remain the
      * same.
      * <P>
-     * The underlying memory used by the <code>srcs</code> and
-     * <code>dst ByteBuffer</code>s must not be the same.
+     * The underlying memory used by the {@code srcs} and
+     * {@code dst ByteBuffer}s must not be the same.
      * <P>
      * See the class description for more information on engine closure.
      *
      * @param   srcs
-     *          an array of <code>ByteBuffers</code> containing the
+     *          an array of {@code ByteBuffers} containing the
      *          outbound application data
      * @param   offset
      *          The offset within the buffer array of the first buffer from
      *          which bytes are to be retrieved; it must be non-negative
-     *          and no larger than <code>srcs.length</code>
+     *          and no larger than {@code srcs.length}
      * @param   length
      *          The maximum number of buffers to be accessed; it must be
      *          non-negative and no larger than
-     *          <code>srcs.length</code>&nbsp;-&nbsp;<code>offset</code>
+     *          {@code srcs.length}&nbsp;-&nbsp;{@code offset}
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold outbound network data
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold outbound network data
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  IndexOutOfBoundsException
-     *          if the preconditions on the <code>offset</code> and
-     *          <code>length</code> parameters do not hold.
+     *          if the preconditions on the {@code offset} and
+     *          {@code length} parameters do not hold.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>srcs</code> or <code>dst</code>
-     *          is null, or if any element in the <code>srcs</code>
+     *          if either {@code srcs} or {@code dst}
+     *          is null, or if any element in the {@code srcs}
      *          subsequence specified is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -589,7 +589,7 @@
             int length, ByteBuffer dst) throws SSLException;
 
     /**
-     * Attempts to decode SSL/TLS network data into a plaintext
+     * Attempts to decode SSL/TLS/DTLS network data into a plaintext
      * application data buffer.
      * <P>
      * An invocation of this method behaves in exactly the same manner
@@ -600,20 +600,20 @@
      * </pre></blockquote>
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing inbound network data.
+     *          a {@code ByteBuffer} containing inbound network data.
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold inbound application data.
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold inbound application data.
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dst</code>
+     *          if either {@code src} or {@code dst}
      *          is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -625,7 +625,7 @@
     }
 
     /**
-     * Attempts to decode SSL/TLS network data into a sequence of plaintext
+     * Attempts to decode SSL/TLS/DTLS network data into a sequence of plaintext
      * application data buffers.
      * <P>
      * An invocation of this method behaves in exactly the same manner
@@ -636,22 +636,22 @@
      * </pre></blockquote>
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing inbound network data.
+     *          a {@code ByteBuffer} containing inbound network data.
      * @param   dsts
-     *          an array of <code>ByteBuffer</code>s to hold inbound
+     *          an array of {@code ByteBuffer}s to hold inbound
      *          application data.
-     * @return  an <code>SSLEngineResult</code> describing the result
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if any of the <code>dst</code> buffers are read-only.
+     *          if any of the {@code dst} buffers are read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dsts</code>
-     *          is null, or if any element in <code>dsts</code> is null.
+     *          if either {@code src} or {@code dsts}
+     *          is null, or if any element in {@code dsts} is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
      * @see     #unwrap(ByteBuffer, ByteBuffer [], int, int)
@@ -665,7 +665,7 @@
     }
 
     /**
-     * Attempts to decode SSL/TLS network data into a subsequence of
+     * Attempts to decode SSL/TLS/DTLS network data into a subsequence of
      * plaintext application data buffers.  This <i>"scattering"</i>
      * operation decodes, in a single invocation, a sequence of bytes
      * into one or more of a given sequence of buffers.  Scattering
@@ -688,55 +688,55 @@
      * order it was received.  The application must properly synchronize
      * multiple calls to this method.
      * <P>
-     * If this <code>SSLEngine</code> has not yet started its initial
+     * If this {@code SSLEngine} has not yet started its initial
      * handshake, this method will automatically start the handshake.
      * <P>
-     * This method will attempt to consume one complete SSL/TLS network
+     * This method will attempt to consume one complete SSL/TLS/DTLS network
      * packet, but will never consume more than the sum of the bytes
-     * remaining in the buffers.  Each <code>ByteBuffer</code>'s
+     * remaining in the buffers.  Each {@code ByteBuffer}'s
      * position is updated to reflect the amount of data consumed or
      * produced.  The limits remain the same.
      * <P>
-     * The underlying memory used by the <code>src</code> and
-     * <code>dsts ByteBuffer</code>s must not be the same.
+     * The underlying memory used by the {@code src} and
+     * {@code dsts ByteBuffer}s must not be the same.
      * <P>
      * The inbound network buffer may be modified as a result of this
      * call:  therefore if the network data packet is required for some
      * secondary purpose, the data should be duplicated before calling this
      * method.  Note:  the network data will not be useful to a second
      * SSLEngine, as each SSLEngine contains unique random state which
-     * influences the SSL/TLS messages.
+     * influences the SSL/TLS/DTLS messages.
      * <P>
      * See the class description for more information on engine closure.
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing inbound network data.
+     *          a {@code ByteBuffer} containing inbound network data.
      * @param   dsts
-     *          an array of <code>ByteBuffer</code>s to hold inbound
+     *          an array of {@code ByteBuffer}s to hold inbound
      *          application data.
      * @param   offset
      *          The offset within the buffer array of the first buffer from
      *          which bytes are to be transferred; it must be non-negative
-     *          and no larger than <code>dsts.length</code>.
+     *          and no larger than {@code dsts.length}.
      * @param   length
      *          The maximum number of buffers to be accessed; it must be
      *          non-negative and no larger than
-     *          <code>dsts.length</code>&nbsp;-&nbsp;<code>offset</code>.
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          {@code dsts.length}&nbsp;-&nbsp;{@code offset}.
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  IndexOutOfBoundsException
-     *          If the preconditions on the <code>offset</code> and
-     *          <code>length</code> parameters do not hold.
+     *          If the preconditions on the {@code offset} and
+     *          {@code length} parameters do not hold.
      * @throws  ReadOnlyBufferException
-     *          if any of the <code>dst</code> buffers are read-only.
+     *          if any of the {@code dst} buffers are read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dsts</code>
-     *          is null, or if any element in the <code>dsts</code>
+     *          if either {@code src} or {@code dsts}
+     *          is null, or if any element in the {@code dsts}
      *          subsequence specified is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -749,19 +749,19 @@
 
 
     /**
-     * Returns a delegated <code>Runnable</code> task for
-     * this <code>SSLEngine</code>.
+     * Returns a delegated {@code Runnable} task for
+     * this {@code SSLEngine}.
      * <P>
-     * <code>SSLEngine</code> operations may require the results of
+     * {@code SSLEngine} operations may require the results of
      * operations that block, or may take an extended period of time to
      * complete.  This method is used to obtain an outstanding {@link
      * java.lang.Runnable} operation (task).  Each task must be assigned
      * a thread (possibly the current) to perform the {@link
      * java.lang.Runnable#run() run} operation.  Once the
-     * <code>run</code> method returns, the <code>Runnable</code> object
+     * {@code run} method returns, the {@code Runnable} object
      * is no longer needed and may be discarded.
      * <P>
-     * Delegated tasks run in the <code>AccessControlContext</code>
+     * Delegated tasks run in the {@code AccessControlContext}
      * in place when this object was created.
      * <P>
      * A call to this method will return each outstanding task
@@ -769,7 +769,7 @@
      * <P>
      * Multiple delegated tasks can be run in parallel.
      *
-     * @return  a delegated <code>Runnable</code> task, or null
+     * @return  a delegated {@code Runnable} task, or null
      *          if none are available.
      */
     public abstract Runnable getDelegatedTask();
@@ -777,7 +777,7 @@
 
     /**
      * Signals that no more inbound network data will be sent
-     * to this <code>SSLEngine</code>.
+     * to this {@code SSLEngine}.
      * <P>
      * If the application initiated the closing process by calling
      * {@link #closeOutbound()}, under some circumstances it is not
@@ -789,9 +789,9 @@
      * <P>
      * But if the application did not initiate the closure process, or
      * if the circumstances above do not apply, this method should be
-     * called whenever the end of the SSL/TLS data stream is reached.
+     * called whenever the end of the SSL/TLS/DTLS data stream is reached.
      * This ensures closure of the inbound side, and checks that the
-     * peer followed the SSL/TLS close procedure properly, thus
+     * peer followed the SSL/TLS/DTLS close procedure properly, thus
      * detecting possible truncation attacks.
      * <P>
      * This method is idempotent:  if the inbound side has already
@@ -801,7 +801,7 @@
      * called to flush any remaining handshake data.
      *
      * @throws  SSLException
-     *          if this engine has not received the proper SSL/TLS close
+     *          if this engine has not received the proper SSL/TLS/DTLS close
      *          notification message from the peer.
      *
      * @see     #isInboundDone()
@@ -814,7 +814,7 @@
      * Returns whether {@link #unwrap(ByteBuffer, ByteBuffer)} will
      * accept any more inbound data messages.
      *
-     * @return  true if the <code>SSLEngine</code> will not
+     * @return  true if the {@code SSLEngine} will not
      *          consume anymore network data (and by implication,
      *          will not produce any more application data.)
      * @see     #closeInbound()
@@ -824,7 +824,7 @@
 
     /**
      * Signals that no more outbound application data will be sent
-     * on this <code>SSLEngine</code>.
+     * on this {@code SSLEngine}.
      * <P>
      * This method is idempotent:  if the outbound side has already
      * been closed, this method does not do anything.
@@ -841,12 +841,12 @@
      * Returns whether {@link #wrap(ByteBuffer, ByteBuffer)} will
      * produce any more outbound data messages.
      * <P>
-     * Note that during the closure phase, a <code>SSLEngine</code> may
+     * Note that during the closure phase, a {@code SSLEngine} may
      * generate handshake closure data that must be sent to the peer.
-     * <code>wrap()</code> must be called to generate this data.  When
+     * {@code wrap()} must be called to generate this data.  When
      * this method returns true, no more outbound data will be created.
      *
-     * @return  true if the <code>SSLEngine</code> will not produce
+     * @return  true if the {@code SSLEngine} will not produce
      *          any more network data
      *
      * @see     #closeOutbound()
@@ -890,10 +890,10 @@
     /**
      * Sets the cipher suites enabled for use on this engine.
      * <P>
-     * Each cipher suite in the <code>suites</code> parameter must have
+     * Each cipher suite in the {@code suites} parameter must have
      * been listed by getSupportedCipherSuites(), or the method will
      * fail.  Following a successful call to this method, only suites
-     * listed in the <code>suites</code> parameter are enabled for use.
+     * listed in the {@code suites} parameter are enabled for use.
      * <P>
      * See {@link #getEnabledCipherSuites()} for more information
      * on why a specific cipher suite may never be used on a engine.
@@ -910,7 +910,7 @@
 
     /**
      * Returns the names of the protocols which could be enabled for use
-     * with this <code>SSLEngine</code>.
+     * with this {@code SSLEngine}.
      *
      * @return  an array of protocols supported
      */
@@ -919,7 +919,7 @@
 
     /**
      * Returns the names of the protocol versions which are currently
-     * enabled for use with this <code>SSLEngine</code>.
+     * enabled for use with this {@code SSLEngine}.
      *
      * @return  an array of protocols
      * @see     #setEnabledProtocols(String [])
@@ -932,7 +932,7 @@
      * <P>
      * The protocols must have been listed by getSupportedProtocols()
      * as being supported.  Following a successful call to this method,
-     * only protocols listed in the <code>protocols</code> parameter
+     * only protocols listed in the {@code protocols} parameter
      * are enabled for use.
      *
      * @param   protocols Names of all the protocols to enable.
@@ -945,8 +945,8 @@
 
 
     /**
-     * Returns the <code>SSLSession</code> in use in this
-     * <code>SSLEngine</code>.
+     * Returns the {@code SSLSession} in use in this
+     * {@code SSLEngine}.
      * <P>
      * These can be long lived, and frequently correspond to an entire
      * login session for some user.  The session specifies a particular
@@ -961,22 +961,22 @@
      * a session object which reports an invalid cipher suite of
      * "SSL_NULL_WITH_NULL_NULL".
      *
-     * @return  the <code>SSLSession</code> for this <code>SSLEngine</code>
+     * @return  the {@code SSLSession} for this {@code SSLEngine}
      * @see     SSLSession
      */
     public abstract SSLSession getSession();
 
 
     /**
-     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS/DTLS
      * handshake.
      * <p>
-     * TLS protocols may negotiate parameters that are needed when using
+     * TLS/DTLS protocols may negotiate parameters that are needed when using
      * an instance of this class, but before the {@code SSLSession} has
      * been completely initialized and made available via {@code getSession}.
      * For example, the list of valid signature algorithms may restrict
      * the type of certificates that can used during TrustManager
-     * decisions, or the maximum TLS fragment packet sizes can be
+     * decisions, or the maximum TLS/DTLS fragment packet sizes can be
      * resized to better support the network environment.
      * <p>
      * This method provides early access to the {@code SSLSession} being
@@ -1012,26 +1012,26 @@
      * Initiates handshaking (initial or renegotiation) on this SSLEngine.
      * <P>
      * This method is not needed for the initial handshake, as the
-     * <code>wrap()</code> and <code>unwrap()</code> methods will
+     * {@code wrap()} and {@code unwrap()} methods will
      * implicitly call this method if handshaking has not already begun.
      * <P>
      * Note that the peer may also request a session renegotiation with
-     * this <code>SSLEngine</code> by sending the appropriate
+     * this {@code SSLEngine} by sending the appropriate
      * session renegotiate handshake message.
      * <P>
      * Unlike the {@link SSLSocket#startHandshake()
      * SSLSocket#startHandshake()} method, this method does not block
      * until handshaking is completed.
      * <P>
-     * To force a complete SSL/TLS session renegotiation, the current
+     * To force a complete SSL/TLS/DTLS session renegotiation, the current
      * session should be invalidated prior to calling this method.
      * <P>
      * Some protocols may not support multiple handshakes on an existing
-     * engine and may throw an <code>SSLException</code>.
+     * engine and may throw an {@code SSLException}.
      *
      * @throws  SSLException
      *          if a problem was encountered while signaling the
-     *          <code>SSLEngine</code> to begin a new handshake.
+     *          {@code SSLEngine} to begin a new handshake.
      *          See the class description for more information on
      *          engine closure.
      * @throws  IllegalStateException if the client/server mode
@@ -1042,9 +1042,9 @@
 
 
     /**
-     * Returns the current handshake status for this <code>SSLEngine</code>.
+     * Returns the current handshake status for this {@code SSLEngine}.
      *
-     * @return  the current <code>SSLEngineResult.HandshakeStatus</code>.
+     * @return  the current {@code SSLEngineResult.HandshakeStatus}.
      */
     public abstract SSLEngineResult.HandshakeStatus getHandshakeStatus();
 
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,13 +27,13 @@
 
 /**
  * An encapsulation of the result state produced by
- * <code>SSLEngine</code> I/O calls.
+ * {@code SSLEngine} I/O calls.
  *
- * <p> A <code>SSLEngine</code> provides a means for establishing
- * secure communication sessions between two peers.  <code>SSLEngine</code>
+ * <p> A {@code SSLEngine} provides a means for establishing
+ * secure communication sessions between two peers.  {@code SSLEngine}
  * operations typically consume bytes from an input buffer and produce
  * bytes in an output buffer.  This class provides operational result
- * values describing the state of the <code>SSLEngine</code>, including
+ * values describing the state of the {@code SSLEngine}, including
  * indications of what operations are needed to finish an
  * ongoing handshake.  Lastly, it reports the number of bytes consumed
  * and produced as a result of this operation.
@@ -49,12 +49,12 @@
 public class SSLEngineResult {
 
     /**
-     * An <code>SSLEngineResult</code> enum describing the overall result
-     * of the <code>SSLEngine</code> operation.
+     * An {@code SSLEngineResult} enum describing the overall result
+     * of the {@code SSLEngine} operation.
      *
-     * The <code>Status</code> value does not reflect the
-     * state of a <code>SSLEngine</code> handshake currently
-     * in progress.  The <code>SSLEngineResult's HandshakeStatus</code>
+     * The {@code Status} value does not reflect the
+     * state of a {@code SSLEngine} handshake currently
+     * in progress.  The {@code SSLEngineResult's HandshakeStatus}
      * should be consulted for that information.
      *
      * @author Brad R. Wetmore
@@ -63,7 +63,7 @@
     public static enum Status {
 
         /**
-         * The <code>SSLEngine</code> was not able to unwrap the
+         * The {@code SSLEngine} was not able to unwrap the
          * incoming data because there were not enough source bytes
          * available to make a complete packet.
          *
@@ -73,7 +73,7 @@
         BUFFER_UNDERFLOW,
 
         /**
-         * The <code>SSLEngine</code> was not able to process the
+         * The {@code SSLEngine} was not able to process the
          * operation because there are not enough bytes available in the
          * destination buffer to hold the result.
          * <P>
@@ -85,22 +85,22 @@
         BUFFER_OVERFLOW,
 
         /**
-         * The <code>SSLEngine</code> completed the operation, and
+         * The {@code SSLEngine} completed the operation, and
          * is available to process similar calls.
          */
         OK,
 
         /**
          * The operation just closed this side of the
-         * <code>SSLEngine</code>, or the operation
+         * {@code SSLEngine}, or the operation
          * could not be completed because it was already closed.
          */
         CLOSED;
     }
 
     /**
-     * An <code>SSLEngineResult</code> enum describing the current
-     * handshaking state of this <code>SSLEngine</code>.
+     * An {@code SSLEngineResult} enum describing the current
+     * handshaking state of this {@code SSLEngine}.
      *
      * @author Brad R. Wetmore
      * @since 1.5
@@ -108,17 +108,17 @@
     public static enum HandshakeStatus {
 
         /**
-         * The <code>SSLEngine</code> is not currently handshaking.
+         * The {@code SSLEngine} is not currently handshaking.
          */
         NOT_HANDSHAKING,
 
         /**
-         * The <code>SSLEngine</code> has just finished handshaking.
+         * The {@code SSLEngine} has just finished handshaking.
          * <P>
          * This value is only generated by a call to
-         * <code>SSLEngine.wrap()/unwrap()</code> when that call
+         * {@code SSLEngine.wrap()/unwrap()} when that call
          * finishes a handshake.  It is never generated by
-         * <code>SSLEngine.getHandshakeStatus()</code>.
+         * {@code SSLEngine.getHandshakeStatus()}.
          *
          * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
          * @see SSLEngine#unwrap(ByteBuffer, ByteBuffer)
@@ -127,7 +127,7 @@
         FINISHED,
 
         /**
-         * The <code>SSLEngine</code> needs the results of one (or more)
+         * The {@code SSLEngine} needs the results of one (or more)
          * delegated tasks before handshaking can continue.
          *
          * @see SSLEngine#getDelegatedTask()
@@ -135,8 +135,8 @@
         NEED_TASK,
 
         /**
-         * The <code>SSLEngine</code> must send data to the remote side
-         * before handshaking can continue, so <code>SSLEngine.wrap()</code>
+         * The {@code SSLEngine} must send data to the remote side
+         * before handshaking can continue, so {@code SSLEngine.wrap()}
          * should be called.
          *
          * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
@@ -144,10 +144,22 @@
         NEED_WRAP,
 
         /**
-         * The <code>SSLEngine</code> needs to receive data from the
+         * The {@code SSLEngine} needs to receive data from the
          * remote side before handshaking can continue.
          */
-        NEED_UNWRAP;
+        NEED_UNWRAP,
+
+        /**
+         * The {@code SSLEngine} needs to unwrap before handshaking can
+         * can continue.
+         * <P>
+         * This value is used to indicate that not-yet-interpreted data
+         * has been previously received from the remote side, and does
+         * not need to be received again.
+         *
+         * @since   1.9
+         */
+        NEED_UNWRAP_AGAIN;
     }
 
 
@@ -155,6 +167,7 @@
     private final HandshakeStatus handshakeStatus;
     private final int bytesConsumed;
     private final int bytesProduced;
+    private final long sequenceNumber;
 
     /**
      * Initializes a new instance of this class.
@@ -172,12 +185,44 @@
      *          the number of bytes placed into the destination ByteBuffer
      *
      * @throws  IllegalArgumentException
-     *          if the <code>status</code> or <code>handshakeStatus</code>
-     *          arguments are null, or if <code>bytesConsumed</code> or
-     *          <code>bytesProduced</code> is negative.
+     *          if the {@code status} or {@code handshakeStatus}
+     *          arguments are null, or if {@code bytesConsumed} or
+     *          {@code bytesProduced} is negative.
      */
     public SSLEngineResult(Status status, HandshakeStatus handshakeStatus,
             int bytesConsumed, int bytesProduced) {
+        this(status, handshakeStatus, bytesConsumed, bytesProduced, -1);
+    }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param   status
+     *          the return value of the operation.
+     *
+     * @param   handshakeStatus
+     *          the current handshaking status.
+     *
+     * @param   bytesConsumed
+     *          the number of bytes consumed from the source ByteBuffer
+     *
+     * @param   bytesProduced
+     *          the number of bytes placed into the destination ByteBuffer
+     *
+     * @param   sequenceNumber
+     *          the sequence number (unsigned long) of the produced or
+     *          consumed SSL/TLS/DTLS record, or ${@code -1L} if no record
+     *          produced or consumed
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code status} or {@code handshakeStatus}
+     *          arguments are null, or if {@code bytesConsumed} or
+     *          {@code bytesProduced} is negative
+     *
+     * @since   1.9
+     */
+    public SSLEngineResult(Status status, HandshakeStatus handshakeStatus,
+            int bytesConsumed, int bytesProduced, long sequenceNumber) {
 
         if ((status == null) || (handshakeStatus == null) ||
                 (bytesConsumed < 0) || (bytesProduced < 0)) {
@@ -188,10 +233,11 @@
         this.handshakeStatus = handshakeStatus;
         this.bytesConsumed = bytesConsumed;
         this.bytesProduced = bytesProduced;
+        this.sequenceNumber = sequenceNumber;
     }
 
     /**
-     * Gets the return value of this <code>SSLEngine</code> operation.
+     * Gets the return value of this {@code SSLEngine} operation.
      *
      * @return  the return value
      */
@@ -200,7 +246,7 @@
     }
 
     /**
-     * Gets the handshake status of this <code>SSLEngine</code>
+     * Gets the handshake status of this {@code SSLEngine}
      * operation.
      *
      * @return  the handshake status
@@ -228,6 +274,41 @@
     }
 
     /**
+     * Returns the sequence number of the produced or consumed SSL/TLS/DTLS
+     * record (optional operation).
+     *
+     * @apiNote  Note that sequence number is an unsigned long and cannot
+     *           exceed {@code -1L}.  It is desired to use the unsigned
+     *           long comparing mode for comparison of unsigned long values
+     *           (see also {@link java.lang.Long#compareUnsigned()
+     *           Long.compareUnsigned()}).
+     *           <P>
+     *           For DTLS protocols, the first 16 bits of the sequence
+     *           number is a counter value (epoch) that is incremented on
+     *           every cipher state change.  The remaining 48 bits on the
+     *           right side of the sequence number represents the sequence
+     *           of the record, which is maintained separately for each epoch.
+     *
+     * @implNote It is recommended that providers should never allow the
+     *           sequence number incremented to {@code -1L}.  If the sequence
+     *           number is close to wrapping, renegotiate should be requested,
+     *           otherwise the connection should be closed immediately.
+     *           This should be carried on automatically by the underlying
+     *           implementation.
+     *
+     * @return  the sequence number of the produced or consumed SSL/TLS/DTLS
+     *          record; or ${@code -1L} if no record is produced or consumed,
+     *          or this operation is not supported by the underlying provider
+     *
+     * @see     java.lang.Long#compareUnsigned(boolean, boolean)
+     *
+     * @since   1.9
+     */
+    final public long sequenceNumber() {
+        return sequenceNumber;
+    }
+
+    /**
      * Returns a String representation of this object.
      */
     @Override
@@ -235,6 +316,8 @@
         return ("Status = " + status +
             " HandshakeStatus = " + handshakeStatus +
             "\nbytesConsumed = " + bytesConsumed +
-            " bytesProduced = " + bytesProduced);
+            " bytesProduced = " + bytesProduced +
+            (sequenceNumber == -1 ? "" :
+                " sequenceNumber = " + Long.toUnsignedString(sequenceNumber)));
     }
 }
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLParameters.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLParameters.java	Tue Jun 02 04:01:04 2015 +0000
@@ -35,22 +35,22 @@
 import java.util.LinkedHashMap;
 
 /**
- * Encapsulates parameters for an SSL/TLS connection. The parameters
- * are the list of ciphersuites to be accepted in an SSL/TLS handshake,
+ * Encapsulates parameters for an SSL/TLS/DTLS connection. The parameters
+ * are the list of ciphersuites to be accepted in an SSL/TLS/DTLS handshake,
  * the list of protocols to be allowed, the endpoint identification
- * algorithm during SSL/TLS handshaking, the Server Name Indication (SNI),
- * the algorithm constraints and whether SSL/TLS servers should request
- * or require client authentication, etc.
+ * algorithm during SSL/TLS/DTLS handshaking, the Server Name Indication (SNI),
+ * the maximum network packet size, the algorithm constraints and whether
+ * SSL/TLS/DTLS servers should request or require client authentication, etc.
  * <p>
  * SSLParameters can be created via the constructors in this class.
- * Objects can also be obtained using the <code>getSSLParameters()</code>
+ * Objects can also be obtained using the {@code getSSLParameters()}
  * methods in
  * {@link SSLSocket#getSSLParameters SSLSocket} and
  * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
  * {@link SSLEngine#getSSLParameters SSLEngine} or the
  * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
  * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
- * methods in <code>SSLContext</code>.
+ * methods in {@code SSLContext}.
  * <p>
  * SSLParameters can be applied to a connection via the methods
  * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
@@ -74,14 +74,18 @@
     private Map<Integer, SNIServerName> sniNames = null;
     private Map<Integer, SNIMatcher> sniMatchers = null;
     private boolean preferLocalCipherSuites;
+    private boolean enableRetransmissions = true;
+    private int maximumPacketSize = 0;
 
     /**
      * Constructs SSLParameters.
      * <p>
      * The values of cipherSuites, protocols, cryptographic algorithm
      * constraints, endpoint identification algorithm, server names and
-     * server name matchers are set to <code>null</code>, useCipherSuitesOrder,
-     * wantClientAuth and needClientAuth are set to <code>false</code>.
+     * server name matchers are set to {@code null}; useCipherSuitesOrder,
+     * wantClientAuth and needClientAuth are set to {@code false};
+     * enableRetransmissions is set to {@code true}; maximum network packet
+     * size is set to {@code 0}.
      */
     public SSLParameters() {
         // empty
@@ -92,7 +96,7 @@
      * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
-     * <code>setCipherSuites(cipherSuites);</code>.
+     * {@code setCipherSuites(cipherSuites);}.
      *
      * @param cipherSuites the array of ciphersuites (or null)
      */
@@ -106,7 +110,7 @@
      * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
-     * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
+     * {@code setCipherSuites(cipherSuites); setProtocols(protocols);}.
      *
      * @param cipherSuites the array of ciphersuites (or null)
      * @param protocols the array of protocols (or null)
@@ -171,7 +175,7 @@
 
     /**
      * Sets whether client authentication should be requested. Calling
-     * this method clears the <code>needClientAuth</code> flag.
+     * this method clears the {@code needClientAuth} flag.
      *
      * @param wantClientAuth whether client authentication should be requested
      */
@@ -191,7 +195,7 @@
 
     /**
      * Sets whether client authentication should be required. Calling
-     * this method clears the <code>wantClientAuth</code> flag.
+     * this method clears the {@code wantClientAuth} flag.
      *
      * @param needClientAuth whether client authentication should be required
      */
@@ -218,9 +222,9 @@
      * Sets the cryptographic algorithm constraints, which will be used
      * in addition to any configured by the runtime environment.
      * <p>
-     * If the <code>constraints</code> parameter is non-null, every
+     * If the {@code constraints} parameter is non-null, every
      * cryptographic algorithm, key and algorithm parameters used in the
-     * SSL/TLS handshake must be permitted by the constraints.
+     * SSL/TLS/DTLS handshake must be permitted by the constraints.
      *
      * @param constraints the algorithm constraints (or null)
      *
@@ -249,9 +253,9 @@
     /**
      * Sets the endpoint identification algorithm.
      * <p>
-     * If the <code>algorithm</code> parameter is non-null or non-empty, the
+     * If the {@code algorithm} parameter is non-null or non-empty, the
      * endpoint identification/verification procedures must be handled during
-     * SSL/TLS handshaking.  This is to prevent man-in-the-middle attacks.
+     * SSL/TLS/DTLS handshaking.  This is to prevent man-in-the-middle attacks.
      *
      * @param algorithm The standard string name of the endpoint
      *     identification algorithm (or null).  See Appendix A in the <a href=
@@ -317,7 +321,7 @@
      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
      * operating in client mode.
      * <P>
-     * For SSL/TLS connections, the underlying SSL/TLS provider
+     * For SSL/TLS/DTLS connections, the underlying SSL/TLS/DTLS provider
      * may specify a default value for a certain server name type.  In
      * client mode, it is recommended that, by default, providers should
      * include the server name indication whenever the server can be located
@@ -440,7 +444,7 @@
      *
      * @param honorOrder whether local cipher suites order in
      *        {@code #getCipherSuites} should be honored during
-     *        SSL/TLS handshaking.
+     *        SSL/TLS/DTLS handshaking.
      *
      * @see #getUseCipherSuitesOrder()
      *
@@ -454,7 +458,7 @@
      * Returns whether the local cipher suites preference should be honored.
      *
      * @return whether local cipher suites order in {@code #getCipherSuites}
-     *         should be honored during SSL/TLS handshaking.
+     *         should be honored during SSL/TLS/DTLS handshaking.
      *
      * @see #setUseCipherSuitesOrder(boolean)
      *
@@ -463,5 +467,107 @@
     public final boolean getUseCipherSuitesOrder() {
         return preferLocalCipherSuites;
     }
+
+    /**
+     * Sets whether DTLS handshake retransmissions should be enabled.
+     *
+     * This method only applies to DTLS.
+     *
+     * @param   enableRetransmissions
+     *          {@code true} indicates that DTLS handshake retransmissions
+     *          should be enabled; {@code false} indicates that DTLS handshake
+     *          retransmissions should be disabled
+     *
+     * @see     #getEnableRetransmissions()
+     *
+     * @since 1.9
+     */
+    public void setEnableRetransmissions(boolean enableRetransmissions) {
+        this.enableRetransmissions = enableRetransmissions;
+    }
+
+    /**
+     * Returns whether DTLS handshake retransmissions should be enabled.
+     *
+     * This method only applies to DTLS.
+     *
+     * @return  true, if DTLS handshake retransmissions should be enabled
+     *
+     * @see     #setEnableRetransmissions(boolean)
+     *
+     * @since 1.9
+     */
+    public boolean getEnableRetransmissions() {
+        return enableRetransmissions;
+    }
+
+    /**
+     * Sets the maximum expected network packet size in bytes for
+     * SSL/TLS/DTLS records.
+     *
+     * @apiNote  It is recommended that if possible, the maximum packet size
+     *           should not be less than 256 bytes so that small handshake
+     *           messages, such as HelloVerifyRequests, are not fragmented.
+     *
+     * @implNote If the maximum packet size is too small to hold a minimal
+     *           record, an implementation may attempt to generate as minimal
+     *           records as possible.  However, this may cause a generated
+     *           packet to be larger than the maximum packet size.
+     *
+     * @param   maximumPacketSize
+     *          the maximum expected network packet size in bytes, or
+     *          {@code 0} to use the implicit size that is automatically
+     *          specified by the underlying implementation.
+     * @throws  IllegalArgumentException
+     *          if {@code maximumPacketSize} is negative.
+     *
+     * @see     #getMaximumPacketSize()
+     *
+     * @since 1.9
+     */
+    public void setMaximumPacketSize(int maximumPacketSize) {
+        if (maximumPacketSize < 0) {
+            throw new IllegalArgumentException(
+                "The maximum packet size cannot be negative");
+        }
+
+        this.maximumPacketSize = maximumPacketSize;
+    }
+
+    /**
+     * Returns the maximum expected network packet size in bytes for
+     * SSL/TLS/DTLS records.
+     *
+     * @apiNote  The implicit size may not be a fixed value, especially
+     *           for a DTLS protocols implementation.
+     *
+     * @implNote For SSL/TLS/DTLS connections, the underlying provider
+     *           should calculate and specify the implicit value of the
+     *           maximum expected network packet size if it is not
+     *           configured explicitly.  For any connection populated
+     *           object, this method should never return {@code 0} so
+     *           that applications can retrieve the actual implicit size
+     *           of the underlying implementation.
+     *           <P>
+     *           An implementation should attempt to comply with the maximum
+     *           packet size configuration.  However, if the maximum packet
+     *           size is too small to hold a minimal record, an implementation
+     *           may try to generate as minimal records as possible.  This
+     *           may cause a generated packet to be larger than the maximum
+     *           packet size.
+     *
+     * @return   the maximum expected network packet size, or {@code 0} if
+     *           use the implicit size that is automatically specified by
+     *           the underlying implementation and this object has not been
+     *           populated by any connection.
+     *
+     * @see      #setMaximumPacketSize(int)
+     *
+     * @since 1.9
+     */
+    public int getMaximumPacketSize() {
+        return maximumPacketSize;
+    }
+
 }
 
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Tue Jun 02 04:01:04 2015 +0000
@@ -35,7 +35,7 @@
  * also be replaced by a different session.  Sessions are created, or
  * rejoined, as part of the SSL handshaking protocol. Sessions may be
  * invalidated due to policies affecting security or resource usage,
- * or by an application explicitly calling <code>invalidate</code>.
+ * or by an application explicitly calling {@code invalidate}.
  * Session management policies are typically used to tune performance.
  *
  * <P> In addition to the standard session attributes, SSL sessions expose
@@ -82,8 +82,8 @@
      * security manager installed, the caller may require
      * permission to access it or a security exception may be thrown.
      * In a Java environment, the security manager's
-     * <code>checkPermission</code> method is called with a
-     * <code>SSLPermission("getSSLSessionContext")</code> permission.
+     * {@code checkPermission} method is called with a
+     * {@code SSLPermission("getSSLSessionContext")} permission.
      *
      * @throws SecurityException if the calling thread does not have
      *         permission to get SSL session context.
@@ -148,14 +148,14 @@
 
     /**
      *
-     * Binds the specified <code>value</code> object into the
+     * Binds the specified {@code value} object into the
      * session's application layer data
-     * with the given <code>name</code>.
+     * with the given {@code name}.
      * <P>
-     * Any existing binding using the same <code>name</code> is
-     * replaced.  If the new (or existing) <code>value</code> implements the
-     * <code>SSLSessionBindingListener</code> interface, the object
-     * represented by <code>value</code> is notified appropriately.
+     * Any existing binding using the same {@code name} is
+     * replaced.  If the new (or existing) {@code value} implements the
+     * {@code SSLSessionBindingListener} interface, the object
+     * represented by {@code value} is notified appropriately.
      * <p>
      * For security reasons, the same named values may not be
      * visible across different access control contexts.
@@ -187,7 +187,7 @@
      * Removes the object bound to the given name in the session's
      * application layer data.  Does nothing if there is no object
      * bound to the given name.  If the bound existing object
-     * implements the <code>SessionBindingListener</code> interface,
+     * implements the {@code SessionBindingListener} interface,
      * it is notified appropriately.
      * <p>
      * For security reasons, the same named values may not be
@@ -349,7 +349,7 @@
      * by this method.
      * <P>
      * This value is not authenticated and should not be relied upon.
-     * It is mainly used as a hint for <code>SSLSession</code> caching
+     * It is mainly used as a hint for {@code SSLSession} caching
      * strategies.
      *
      * @return  the host name of the peer host, or null if no information
@@ -364,7 +364,7 @@
      * the client, it is the server's port number.
      * <P>
      * This value is not authenticated and should not be relied upon.
-     * It is mainly used as a hint for <code>SSLSession</code> caching
+     * It is mainly used as a hint for {@code SSLSession} caching
      * strategies.
      *
      * @return  the port number of the peer host, or -1 if no information
@@ -375,14 +375,14 @@
     public int getPeerPort();
 
     /**
-     * Gets the current size of the largest SSL/TLS packet that is expected
-     * when using this session.
+     * Gets the current size of the largest SSL/TLS/DTLS packet that is
+     * expected when using this session.
      * <P>
-     * A <code>SSLEngine</code> using this session may generate SSL/TLS
+     * An {@code SSLEngine} using this session may generate SSL/TLS/DTLS
      * packets of any size up to and including the value returned by this
-     * method. All <code>SSLEngine</code> network buffers should be sized
+     * method. All {@code SSLEngine} network buffers should be sized
      * at least this large to avoid insufficient space problems when
-     * performing <code>wrap</code> and <code>unwrap</code> calls.
+     * performing {@code wrap} and {@code unwrap} calls.
      *
      * @return  the current maximum expected network packet size
      *
@@ -398,7 +398,7 @@
      * Gets the current size of the largest application data that is
      * expected when using this session.
      * <P>
-     * <code>SSLEngine</code> application data buffers must be large
+     * {@code SSLEngine} application data buffers must be large
      * enough to hold the application data from any inbound network
      * application data packet received.  Typically, outbound
      * application data buffers can be of any size.
--- a/jdk/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,16 +32,17 @@
 import java.security.cert.CertificateException;
 
 /**
- * Extensions to the <code>X509TrustManager</code> interface to support
- * SSL/TLS connection sensitive trust management.
+ * Extensions to the {@code X509TrustManager} interface to support
+ * SSL/TLS/DTLS connection sensitive trust management.
  * <p>
  * To prevent man-in-the-middle attacks, hostname checks can be done
  * to verify that the hostname in an end-entity certificate matches the
- * targeted hostname.  TLS does not require such checks, but some protocols
- * over TLS (such as HTTPS) do.  In earlier versions of the JDK, the
- * certificate chain checks were done at the SSL/TLS layer, and the hostname
- * verification checks were done at the layer over TLS.  This class allows
- * for the checking to be done during a single call to this class.
+ * targeted hostname.  TLS/DTLS does not require such checks, but some
+ * protocols over TLS/DTLS (such as HTTPS) do.  In earlier versions of the
+ * JDK, the certificate chain checks were done at the SSL/TLS/DTLS layer,
+ * and the hostname verification checks were done at the layer over TLS/DTLS.
+ * This class allows for the checking to be done during a single call to
+ * this class.
  * <p>
  * RFC 2830 defines the server identification specification for the "LDAPS"
  * algorithm. RFC 2818 defines both the server identification and the
@@ -62,17 +63,17 @@
      * used. For instance, if RSAPublicKey is used, the authType
      * should be "RSA". Checking is case-sensitive.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the endpoint identification
-     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
-     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * algorithm of the {@code SSLParameters} is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the {@code socket}
      * connected to should be checked against the peer's identity presented
      * in the end-entity X509 certificate, as specified in the endpoint
      * identification algorithm.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the algorithm constraints of the
-     * <code>SSLParameters</code> is non-null, for every certificate in the
+     * {@code SSLParameters} is non-null, for every certificate in the
      * certification path, fields such as subject public key, the signature
      * algorithm, key usage, extended key usage, etc. need to conform to the
      * algorithm constraints in place on this socket.
@@ -83,8 +84,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
@@ -110,17 +111,17 @@
      * used for the key exchange, and RSA when the key from the server
      * certificate is used. Checking is case-sensitive.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the endpoint identification
-     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
-     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * algorithm of the {@code SSLParameters} is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the {@code socket}
      * connected to should be checked against the peer's identity presented
      * in the end-entity X509 certificate, as specified in the endpoint
      * identification algorithm.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the algorithm constraints of the
-     *  <code>SSLParameters</code> is non-null, for every certificate in the
+     *  {@code SSLParameters} is non-null, for every certificate in the
      * certification path, fields such as subject public key, the signature
      * algorithm, key usage, extended key usage, etc. need to conform to the
      * algorithm constraints in place on this socket.
@@ -131,8 +132,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
@@ -153,15 +154,15 @@
      * used. For instance, if RSAPublicKey is used, the authType
      * should be "RSA". Checking is case-sensitive.
      * <p>
-     * If the <code>engine</code> parameter is available, and the endpoint
-     * identification algorithm of the <code>SSLParameters</code> is
+     * If the {@code engine} parameter is available, and the endpoint
+     * identification algorithm of the {@code SSLParameters} is
      * non-empty, to prevent man-in-the-middle attacks, the address that
-     * the <code>engine</code> connected to should be checked against
+     * the {@code engine} connected to should be checked against
      * the peer's identity presented in the end-entity X509 certificate,
      * as specified in the endpoint identification algorithm.
      * <p>
-     * If the <code>engine</code> parameter is available, and the algorithm
-     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * If the {@code engine} parameter is available, and the algorithm
+     * constraints of the {@code SSLParameters} is non-null, for every
      * certificate in the certification path, fields such as subject public
      * key, the signature algorithm, key usage, extended key usage, etc.
      * need to conform to the algorithm constraints in place on this engine.
@@ -172,8 +173,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
@@ -199,15 +200,15 @@
      * used for the key exchange, and RSA when the key from the server
      * certificate is used. Checking is case-sensitive.
      * <p>
-     * If the <code>engine</code> parameter is available, and the endpoint
-     * identification algorithm of the <code>SSLParameters</code> is
+     * If the {@code engine} parameter is available, and the endpoint
+     * identification algorithm of the {@code SSLParameters} is
      * non-empty, to prevent man-in-the-middle attacks, the address that
-     * the <code>engine</code> connected to should be checked against
+     * the {@code engine} connected to should be checked against
      * the peer's identity presented in the end-entity X509 certificate,
      * as specified in the endpoint identification algorithm.
      * <p>
-     * If the <code>engine</code> parameter is available, and the algorithm
-     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * If the {@code engine} parameter is available, and the algorithm
+     * constraints of the {@code SSLParameters} is non-null, for every
      * certificate in the certification path, fields such as subject public
      * key, the signature algorithm, key usage, extended key usage, etc.
      * need to conform to the algorithm constraints in place on this engine.
@@ -218,8 +219,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
--- a/jdk/src/java.base/share/classes/sun/security/ssl/AppInputStream.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/AppInputStream.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,41 +26,54 @@
 
 package sun.security.ssl;
 
-import java.io.*;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLProtocolException;
 
 /**
  * InputStream for application data as returned by SSLSocket.getInputStream().
- * It uses an InputRecord as internal buffer that is refilled on demand
- * whenever it runs out of data.
  *
  * @author David Brownell
  */
-class AppInputStream extends InputStream {
+final class AppInputStream extends InputStream {
+    // the buffer size for each read of network data
+    private static final int READ_BUFFER_SIZE = 4096;
 
     // static dummy array we use to implement skip()
-    private final static byte[] SKIP_ARRAY = new byte[1024];
+    private static final byte[] SKIP_ARRAY = new byte[256];
 
-    private SSLSocketImpl c;
-    InputRecord r;
+    // the related socket of the input stream
+    private final SSLSocketImpl socket;
+
+    // the temporary buffer used to read network
+    private ByteBuffer buffer;
+
+    // Is application data available in the stream?
+    private boolean appDataIsAvailable;
 
     // One element array used to implement the single byte read() method
     private final byte[] oneByte = new byte[1];
 
     AppInputStream(SSLSocketImpl conn) {
-        r = new InputRecord();
-        c = conn;
+        this.buffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
+        this.socket = conn;
+        this.appDataIsAvailable = false;
     }
 
     /**
      * Return the minimum number of bytes that can be read without blocking.
+     *
      * Currently not synchronized.
      */
     @Override
     public int available() throws IOException {
-        if (c.checkEOF() || (r.isAppDataValid() == false)) {
+        if ((!appDataIsAvailable) || socket.checkEOF()) {
             return 0;
         }
-        return r.available();
+
+        return buffer.remaining();
     }
 
     /**
@@ -72,17 +85,21 @@
         if (n <= 0) { // EOF
             return -1;
         }
-        return oneByte[0] & 0xff;
+        return oneByte[0] & 0xFF;
     }
 
     /**
-     * Read up to "len" bytes into this buffer, starting at "off".
+     * Reads up to {@code len} bytes of data from the input stream into an
+     * array of bytes. An attempt is made to read as many as {@code len} bytes,
+     * but a smaller number may be read. The number of bytes actually read
+     * is returned as an integer.
+     *
      * If the layer above needs more data, it asks for more, so we
      * are responsible only for blocking to fill at most one buffer,
      * and returning "-1" on non-fault EOF status.
      */
     @Override
-    public synchronized int read(byte b[], int off, int len)
+    public synchronized int read(byte[] b, int off, int len)
             throws IOException {
         if (b == null) {
             throw new NullPointerException();
@@ -92,28 +109,69 @@
             return 0;
         }
 
-        if (c.checkEOF()) {
+        if (socket.checkEOF()) {
             return -1;
         }
+
+        // Read the available bytes at first.
+        int remains = available();
+        if (remains > 0) {
+            int howmany = Math.min(remains, len);
+            buffer.get(b, off, howmany);
+
+            return howmany;
+        }
+
+        appDataIsAvailable = false;
+        int volume = 0;
+
         try {
             /*
              * Read data if needed ... notice that the connection guarantees
              * that handshake, alert, and change cipher spec data streams are
              * handled as they arrive, so we never see them here.
              */
-            while (r.available() == 0) {
-                c.readDataRecord(r);
-                if (c.checkEOF()) {
+            while(volume == 0) {
+                // Clear the buffer for a new record reading.
+                buffer.clear();
+
+                //
+                // grow the buffer if needed
+                //
+
+                // Read the header of a record into the buffer, and return
+                // the packet size.
+                int packetLen = socket.bytesInCompletePacket();
+                if (packetLen < 0) {    // EOF
                     return -1;
                 }
+
+                // Is this packet bigger than SSL/TLS normally allows?
+                if (packetLen > SSLRecord.maxLargeRecordSize) {
+                    throw new SSLProtocolException(
+                        "Illegal packet size: " + packetLen);
+                }
+
+                if (packetLen > buffer.remaining()) {
+                    buffer = ByteBuffer.allocate(packetLen);
+                }
+
+                volume = socket.readRecord(buffer);
+                if (volume < 0) {    // EOF
+                    return -1;
+                } else if (volume > 0) {
+                    appDataIsAvailable = true;
+                    break;
+                }
             }
 
-            int howmany = Math.min(len, r.available());
-            howmany = r.read(b, off, howmany);
+            int howmany = Math.min(len, volume);
+            buffer.get(b, off, howmany);
             return howmany;
         } catch (Exception e) {
             // shutdown and rethrow (wrapped) exception as appropriate
-            c.handleException(e);
+            socket.handleException(e);
+
             // dummy for compiler
             return -1;
         }
@@ -147,9 +205,8 @@
      */
     @Override
     public void close() throws IOException {
-        c.close();
+        socket.close();
     }
 
     // inherit default mark/reset behavior (throw Exceptions) from InputStream
-
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/AppOutputStream.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/AppOutputStream.java	Tue Jun 02 04:01:04 2015 +0000
@@ -23,41 +23,33 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
 import java.io.OutputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 /*
- * Output stream for application data. This is the kind of stream
- * that's handed out via SSLSocket.getOutputStream(). It's all the application
- * ever sees.
- *
- * Once the initial handshake has completed, application data may be
- * interleaved with handshake data. That is handled internally and remains
- * transparent to the application.
+ * OutputStream for application data as returned by SSLSocket.getOutputStream().
  *
  * @author  David Brownell
  */
 class AppOutputStream extends OutputStream {
 
-    private SSLSocketImpl c;
-    OutputRecord r;
+    private SSLSocketImpl socket;
 
     // One element array used to implement the write(byte) method
     private final byte[] oneByte = new byte[1];
 
     AppOutputStream(SSLSocketImpl conn) {
-        r = new OutputRecord(Record.ct_application_data);
-        c = conn;
+        this.socket = conn;
     }
 
     /**
      * Write the data out, NOW.
      */
     @Override
-    synchronized public void write(byte b[], int off, int len)
+    synchronized public void write(byte[] b, int off, int len)
             throws IOException {
         if (b == null) {
             throw new NullPointerException();
@@ -68,64 +60,15 @@
         }
 
         // check if the Socket is invalid (error or closed)
-        c.checkWrite();
+        socket.checkWrite();
 
-        /*
-         * By default, we counter chosen plaintext issues on CBC mode
-         * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
-         * data in the first record of every payload, and the rest in
-         * subsequent record(s). Note that the issues have been solved in
-         * TLS 1.1 or later.
-         *
-         * It is not necessary to split the very first application record of
-         * a freshly negotiated TLS session, as there is no previous
-         * application data to guess.  To improve compatibility, we will not
-         * split such records.
-         *
-         * This avoids issues in the outbound direction.  For a full fix,
-         * the peer must have similar protections.
-         */
-        boolean isFirstRecordOfThePayload = true;
-
-        // Always flush at the end of each application level record.
-        // This lets application synchronize read and write streams
-        // however they like; if we buffered here, they couldn't.
+        // Delegate the writing to the underlying socket.
         try {
-            do {
-                boolean holdRecord = false;
-                int howmuch;
-                if (isFirstRecordOfThePayload && c.needToSplitPayload()) {
-                    howmuch = Math.min(0x01, r.availableDataBytes());
-                     /*
-                      * Nagle's algorithm (TCP_NODELAY) was coming into
-                      * play here when writing short (split) packets.
-                      * Signal to the OutputRecord code to internally
-                      * buffer this small packet until the next outbound
-                      * packet (of any type) is written.
-                      */
-                     if ((len != 1) && (howmuch == 1)) {
-                         holdRecord = true;
-                     }
-                } else {
-                    howmuch = Math.min(len, r.availableDataBytes());
-                }
-
-                if (isFirstRecordOfThePayload && howmuch != 0) {
-                    isFirstRecordOfThePayload = false;
-                }
-
-                // NOTE: *must* call c.writeRecord() even for howmuch == 0
-                if (howmuch > 0) {
-                    r.write(b, off, howmuch);
-                    off += howmuch;
-                    len -= howmuch;
-                }
-                c.writeRecord(r, holdRecord);
-                c.checkWrite();
-            } while (len > 0);
+            socket.writeRecord(b, off, len);
+            socket.checkWrite();
         } catch (Exception e) {
             // shutdown and rethrow (wrapped) exception as appropriate
-            c.handleException(e);
+            socket.handleException(e);
         }
     }
 
@@ -143,7 +86,7 @@
      */
     @Override
     public void close() throws IOException {
-        c.close();
+        socket.close();
     }
 
     // inherit no-op flush()
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Authenticator.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Authenticator.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,19 +28,26 @@
 import java.util.Arrays;
 
 /**
- * This class represents an SSL/TLS message authentication token,
+ * This class represents an SSL/TLS/DTLS message authentication token,
  * which encapsulates a sequence number and ensures that attempts to
  * delete or reorder messages can be detected.
  *
- * Each SSL/TLS connection state contains a sequence number, which
- * is maintained separately for read and write states.  The sequence
- * number MUST be set to zero whenever a connection state is made the
- * active state.  Sequence numbers are of type uint64 and may not
- * exceed 2^64-1.  Sequence numbers do not wrap.  If a SSL/TLS
- * implementation would need to wrap a sequence number, it must
- * renegotiate instead.  A sequence number is incremented after each
- * record: specifically, the first record transmitted under a
- * particular connection state MUST use sequence number 0.
+ * Each connection state contains a sequence number, which is maintained
+ * separately for read and write states.
+ *
+ * For SSL/TLS protocols, the sequence number MUST be set to zero
+ * whenever a connection state is made the active state.
+ *
+ * DTLS uses an explicit sequence number, rather than an implicit one.
+ * Sequence numbers are maintained separately for each epoch, with
+ * each sequence number initially being 0 for each epoch.  The sequence
+ * number used to compute the DTLS MAC is the 64-bit value formed by
+ * concatenating the epoch and the sequence number.
+ *
+ * Sequence numbers do not wrap.  If an implementation would need to wrap
+ * a sequence number, it must renegotiate instead.  A sequence number is
+ * incremented after each record: specifically, the first record transmitted
+ * under a particular connection state MUST use sequence number 0.
  */
 class Authenticator {
 
@@ -56,13 +63,30 @@
     // sequence number + record type + protocol version + record length
     private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
 
+    // the block size of DTLS v1.0 and later:
+    // epoch + sequence number + record type + protocol version + record length
+    private static final int BLOCK_SIZE_DTLS = 2 + 6 + 1 + 2 + 2;
+
+    private final boolean isDTLS;
+
     /**
      * Default construct, no message authentication token is initialized.
      *
      * Note that this construct can only be called for null MAC
      */
-    Authenticator() {
-        block = new byte[0];
+    protected Authenticator(boolean isDTLS) {
+        if (isDTLS) {
+            // For DTLS protocols, plaintexts use explicit epoch and
+            // sequence number in each record.  The first 8 byte of
+            // the block is initialized for null MAC so that the
+            // epoch and sequence number can be acquired to generate
+            // plaintext records.
+            block = new byte[8];
+        } else {
+            block = new byte[0];
+        }
+
+        this.isDTLS = isDTLS;
     }
 
     /**
@@ -70,12 +94,22 @@
      * SSL/TLS protocol.
      */
     Authenticator(ProtocolVersion protocolVersion) {
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.isDTLSProtocol()) {
+            block = new byte[BLOCK_SIZE_DTLS];
+            block[9] = protocolVersion.major;
+            block[10] = protocolVersion.minor;
+
+            this.isDTLS = true;
+        } else if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
             block = new byte[BLOCK_SIZE_TLS];
             block[9] = protocolVersion.major;
             block[10] = protocolVersion.minor;
+
+            this.isDTLS = false;
         } else {
             block = new byte[BLOCK_SIZE_SSL];
+
+            this.isDTLS = false;
         }
     }
 
@@ -93,11 +127,19 @@
          * Conservatively, we don't allow more records to be generated
          * when there are only 2^8 sequence numbers left.
          */
-        return (block.length != 0 &&
+        if (isDTLS) {
+            return (block.length != 0 &&
+                // no epoch bytes, block[0] and block[1]
+                block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
+                block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
+                block[6] == (byte)0xFF);
+        } else {
+            return (block.length != 0 &&
                 block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
                 block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
                 block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
                 block[6] == (byte)0xFF);
+        }
     }
 
     /**
@@ -113,14 +155,22 @@
     final boolean seqNumIsHuge() {
         /*
          * Conservatively, we should ask for renegotiation when there are
-         * only 2^48 sequence numbers left.
+         * only 2^32 sequence numbers left.
          */
-        return (block.length != 0 &&
-                block[0] == (byte)0xFF && block[1] == (byte)0xFF);
+        if (isDTLS) {
+            return (block.length != 0 &&
+                // no epoch bytes, block[0] and block[1]
+                block[2] == (byte)0xFF && block[3] == (byte)0xFF);
+        } else {
+            return (block.length != 0 &&
+                block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
+                block[2] == (byte)0xFF && block[3] == (byte)0xFF);
+        }
     }
 
     /**
-     * Gets the current sequence number.
+     * Gets the current sequence number, including the epoch number for
+     * DTLS protocols.
      *
      * @return the byte array of the current sequence number
      */
@@ -129,33 +179,83 @@
     }
 
     /**
+     * Sets the epoch number (only apply to DTLS protocols).
+     */
+    final void setEpochNumber(int epoch) {
+        if (!isDTLS) {
+            throw new RuntimeException(
+                "Epoch numbers apply to DTLS protocols only");
+        }
+
+        block[0] = (byte)((epoch >> 8) & 0xFF);
+        block[1] = (byte)(epoch & 0xFF);
+    }
+
+    /**
+     * Increase the sequence number.
+     */
+    final void increaseSequenceNumber() {
+        /*
+         * The sequence number in the block array is a 64-bit
+         * number stored in big-endian format.
+         */
+        int k = 7;
+        while ((k >= 0) && (++block[k] == 0)) {
+            k--;
+        }
+    }
+
+    /**
      * Acquires the current message authentication information with the
      * specified record type and fragment length, and then increases the
      * sequence number.
      *
      * @param  type the record type
      * @param  length the fragment of the record
+     * @param  sequence the explicit sequence number of the record
+     *
      * @return the byte array of the current message authentication information
      */
-    final byte[] acquireAuthenticationBytes(byte type, int length) {
+    final byte[] acquireAuthenticationBytes(
+            byte type, int length, byte[] sequence) {
+
         byte[] copy = block.clone();
+        if (sequence != null) {
+            if (sequence.length != 8) {
+                throw new RuntimeException(
+                        "Insufficient explicit sequence number bytes");
+            }
+
+            System.arraycopy(sequence, 0, copy, 0, sequence.length);
+        }   // Otherwise, use the implicit sequence number.
 
         if (block.length != 0) {
             copy[8] = type;
+
             copy[copy.length - 2] = (byte)(length >> 8);
             copy[copy.length - 1] = (byte)(length);
 
-            /*
-             * Increase the sequence number in the block array
-             * it is a 64-bit number stored in big-endian format
-             */
-            int k = 7;
-            while ((k >= 0) && (++block[k] == 0)) {
-                k--;
+            if (sequence == null || sequence.length != 0) {
+                // Increase the implicit sequence number in the block array.
+                increaseSequenceNumber();
             }
         }
 
         return copy;
     }
 
+    final static long toLong(byte[] recordEnS) {
+        if (recordEnS != null && recordEnS.length == 8) {
+            return ((recordEnS[0] & 0xFFL) << 56) |
+                   ((recordEnS[1] & 0xFFL) << 48) |
+                   ((recordEnS[2] & 0xFFL) << 40) |
+                   ((recordEnS[3] & 0xFFL) << 32) |
+                   ((recordEnS[4] & 0xFFL) << 24) |
+                   ((recordEnS[5] & 0xFFL) << 16) |
+                   ((recordEnS[6] & 0xFFL) <<  8) |
+                    (recordEnS[7] & 0xFFL);
+        }
+
+        return -1L;
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Tue Jun 02 04:01:04 2015 +0000
@@ -154,9 +154,9 @@
      * NULL cipherbox. Identity operation, no encryption.
      */
     private CipherBox() {
-        this.protocolVersion = ProtocolVersion.DEFAULT;
+        this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
         this.cipher = null;
-        this.cipherType = STREAM_CIPHER;
+        this.cipherType = NULL_CIPHER;
         this.fixedIv = new byte[0];
         this.key = null;
         this.mode = Cipher.ENCRYPT_MODE;    // choose at random
@@ -197,7 +197,7 @@
              */
             if (iv == null && bulkCipher.ivSize != 0 &&
                     mode == Cipher.DECRYPT_MODE &&
-                    protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    protocolVersion.useTLS11PlusSpec()) {
                 iv = getFixedMask(bulkCipher.ivSize);
             }
 
@@ -491,7 +491,7 @@
                 newLen = removePadding(
                     buf, offset, newLen, tagLen, blockSize, protocolVersion);
 
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     if (newLen < blockSize) {
                         throw new BadPaddingException("invalid explicit IV");
                     }
@@ -573,7 +573,7 @@
                 newLen = removePadding(bb, tagLen, blockSize, protocolVersion);
 
                 // check the explicit IV of TLS v1.1 or later
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     if (newLen < blockSize) {
                         throw new BadPaddingException("invalid explicit IV");
                     }
@@ -746,7 +746,7 @@
         // The padding data should be filled with the padding length value.
         int[] results = checkPadding(buf, offset + newLen,
                         padLen + 1, (byte)(padLen & 0xFF));
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             if (results[0] != 0) {          // padding data has invalid bytes
                 throw new BadPaddingException("Invalid TLS padding data");
             }
@@ -792,7 +792,7 @@
         int[] results = checkPadding(
                 bb.duplicate().position(offset + newLen),
                 (byte)(padLen & 0xFF));
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             if (results[0] != 0) {          // padding data has invalid bytes
                 throw new BadPaddingException("Invalid TLS padding data");
             }
@@ -873,7 +873,7 @@
                 // For block ciphers, the explicit IV length is of length
                 // SecurityParameters.record_iv_length, which is equal to
                 // the SecurityParameters.block_size.
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     return cipher.getBlockSize();
                 }
                 break;
@@ -902,7 +902,7 @@
      * @return the explicit nonce size of the cipher.
      */
     int applyExplicitNonce(Authenticator authenticator, byte contentType,
-            ByteBuffer bb) throws BadPaddingException {
+            ByteBuffer bb, byte[] sequence) throws BadPaddingException {
         switch (cipherType) {
             case BLOCK_CIPHER:
                 // sanity check length of the ciphertext
@@ -918,7 +918,7 @@
                 // For block ciphers, the explicit IV length is of length
                 // SecurityParameters.record_iv_length, which is equal to
                 // the SecurityParameters.block_size.
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     return cipher.getBlockSize();
                 }
                 break;
@@ -945,7 +945,8 @@
 
                 // update the additional authentication data
                 byte[] aad = authenticator.acquireAuthenticationBytes(
-                        contentType, bb.remaining() - recordIvSize - tagSize);
+                        contentType, bb.remaining() - recordIvSize - tagSize,
+                        sequence);
                 cipher.updateAAD(aad);
 
                 return recordIvSize;
@@ -957,33 +958,6 @@
     }
 
     /*
-     * Applies the explicit nonce/IV to this cipher. This method is used to
-     * decrypt an SSL/TLS input record.
-     *
-     * The returned value is the SecurityParameters.record_iv_length in
-     * RFC 4346/5246.  It is the size of explicit IV for CBC mode, and the
-     * size of explicit nonce for AEAD mode.
-     *
-     * @param  authenticator the authenticator to get the additional
-     *         authentication data
-     * @param  contentType the content type of the input record
-     * @param  buf the byte array to get the explicit nonce from
-     * @param  offset the offset of the byte buffer
-     * @param  cipheredLength the ciphered fragment length of the output
-     *         record, it is the TLSCiphertext.length in RFC 4346/5246.
-     *
-     * @return the explicit nonce size of the cipher.
-     */
-    int applyExplicitNonce(Authenticator authenticator,
-            byte contentType, byte[] buf, int offset,
-            int cipheredLength) throws BadPaddingException {
-
-        ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength);
-
-        return applyExplicitNonce(authenticator, contentType, bb);
-    }
-
-    /*
      * Creates the explicit nonce/IV to this cipher. This method is used to
      * encrypt an SSL/TLS output record.
      *
@@ -1005,7 +979,7 @@
         byte[] nonce = new byte[0];
         switch (cipherType) {
             case BLOCK_CIPHER:
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     // For block ciphers, the explicit IV length is of length
                     // SecurityParameters.record_iv_length, which is equal to
                     // the SecurityParameters.block_size.
@@ -1034,9 +1008,10 @@
                                 "invalid key or spec in GCM mode", ikae);
                 }
 
-                // update the additional authentication data
+                // Update the additional authentication data, using the
+                // implicit sequence number of the authenticator.
                 byte[] aad = authenticator.acquireAuthenticationBytes(
-                                                contentType, fragmentLength);
+                                        contentType, fragmentLength, null);
                 cipher.updateAAD(aad);
                 break;
         }
@@ -1044,6 +1019,93 @@
         return nonce;
     }
 
+    // See also CipherSuite.calculatePacketSize().
+    int calculatePacketSize(int fragmentSize, int macLen, int headerSize) {
+        int packetSize = fragmentSize;
+        if (cipher != null) {
+            int blockSize = cipher.getBlockSize();
+            switch (cipherType) {
+                case BLOCK_CIPHER:
+                    packetSize += macLen;
+                    packetSize += 1;        // 1 byte padding length field
+                    packetSize +=           // use the minimal padding
+                            (blockSize - (packetSize % blockSize)) % blockSize;
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        packetSize += blockSize;        // explicit IV
+                    }
+
+                    break;
+                case AEAD_CIPHER:
+                    packetSize += recordIvSize;
+                    packetSize += tagSize;
+
+                    break;
+                default:    // NULL_CIPHER or STREAM_CIPHER
+                    packetSize += macLen;
+            }
+        }
+
+        return packetSize + headerSize;
+    }
+
+    // See also CipherSuite.calculateFragSize().
+    int calculateFragmentSize(int packetLimit, int macLen, int headerSize) {
+        int fragLen = packetLimit - headerSize;
+        if (cipher != null) {
+            int blockSize = cipher.getBlockSize();
+            switch (cipherType) {
+                case BLOCK_CIPHER:
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        fragLen -= blockSize;           // explicit IV
+                    }
+                    fragLen -= (fragLen % blockSize);   // cannot hold a block
+                    // No padding for a maximum fragment.
+                    fragLen -= 1;       // 1 byte padding length field: 0x00
+                    fragLen -= macLen;
+
+                    break;
+                case AEAD_CIPHER:
+                    fragLen -= recordIvSize;
+                    fragLen -= tagSize;
+
+                    break;
+                default:    // NULL_CIPHER or STREAM_CIPHER
+                    fragLen -= macLen;
+            }
+        }
+
+        return fragLen;
+    }
+
+    // Estimate the maximum fragment size of a received packet.
+    int estimateFragmentSize(int packetSize, int macLen, int headerSize) {
+        int fragLen = packetSize - headerSize;
+        if (cipher != null) {
+            int blockSize = cipher.getBlockSize();
+            switch (cipherType) {
+                case BLOCK_CIPHER:
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        fragLen -= blockSize;       // explicit IV
+                    }
+                    // No padding for a maximum fragment.
+                    fragLen -= 1;       // 1 byte padding length field: 0x00
+                    fragLen -= macLen;
+
+                    break;
+                case AEAD_CIPHER:
+                    fragLen -= recordIvSize;
+                    fragLen -= tagSize;
+
+                    break;
+                default:    // NULL_CIPHER or STREAM_CIPHER
+                    fragLen -= macLen;
+            }
+        }
+
+        return fragLen;
+    }
+
+
     /*
      * Is this cipher available?
      *
@@ -1100,7 +1162,7 @@
         if ((fragmentLen % blockSize) == 0) {
             int minimal = tagLen + 1;
             minimal = (minimal >= blockSize) ? minimal : blockSize;
-            if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+            if (protocolVersion.useTLS11PlusSpec()) {
                 minimal += blockSize;   // plus the size of the explicit IV
             }
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Tue Jun 02 04:01:04 2015 +0000
@@ -122,9 +122,15 @@
     final boolean allowed;
 
     // obsoleted since protocol version
+    //
+    // TLS version is used.  If checking DTLS versions, please map to
+    // TLS version firstly.  See ProtocolVersion.mapToTLSProtocol().
     final int obsoleted;
 
-    // supported since protocol version
+    // supported since protocol version (TLS version is used)
+    //
+    // TLS version is used.  If checking DTLS versions, please map to
+    // TLS version firstly.  See ProtocolVersion.mapToTLSProtocol().
     final int supported;
 
     /**
@@ -182,6 +188,70 @@
         return this != C_SCSV && isAvailable();
     }
 
+    // See also CipherBox.calculatePacketSize().
+    int calculatePacketSize(int fragmentSize,
+            ProtocolVersion protocolVersion, boolean isDTLS) {
+
+        int packetSize = fragmentSize;
+        if (cipher != B_NULL) {
+            int blockSize = cipher.ivSize;
+            switch (cipher.cipherType) {
+                case BLOCK_CIPHER:
+                    packetSize += macAlg.size;
+                    packetSize += 1;        // 1 byte padding length field
+                    packetSize +=           // use the minimal padding
+                            (blockSize - (packetSize % blockSize)) % blockSize;
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        packetSize += blockSize;        // explicit IV
+                    }
+
+                    break;
+            case AEAD_CIPHER:
+                packetSize += cipher.ivSize - cipher.fixedIvSize;   // record IV
+                packetSize += cipher.tagSize;
+
+                break;
+            default:    // NULL_CIPHER or STREAM_CIPHER
+                packetSize += macAlg.size;
+            }
+        }
+
+        return packetSize +
+            (isDTLS ? DTLSRecord.headerSize : SSLRecord.headerSize);
+    }
+
+    // See also CipherBox.calculateFragmentSize().
+    int calculateFragSize(int packetLimit,
+            ProtocolVersion protocolVersion, boolean isDTLS) {
+
+        int fragSize = packetLimit -
+                (isDTLS ? DTLSRecord.headerSize : SSLRecord.headerSize);
+        if (cipher != B_NULL) {
+            int blockSize = cipher.ivSize;
+            switch (cipher.cipherType) {
+            case BLOCK_CIPHER:
+                if (protocolVersion.useTLS11PlusSpec()) {
+                    fragSize -= blockSize;              // explicit IV
+                }
+                fragSize -= (fragSize % blockSize);     // cannot hold a block
+                // No padding for a maximum fragment.
+                fragSize -= 1;        // 1 byte padding length field: 0x00
+                fragSize -= macAlg.size;
+
+                break;
+            case AEAD_CIPHER:
+                fragSize -= cipher.tagSize;
+                fragSize -= cipher.ivSize - cipher.fixedIvSize;     // record IV
+
+                break;
+            default:    // NULL_CIPHER or STREAM_CIPHER
+                fragSize -= macAlg.size;
+            }
+        }
+
+        return fragSize;
+    }
+
     /**
      * Compares CipherSuites based on their priority. Has the effect of
      * sorting CipherSuites when put in a sorted collection, which is
@@ -242,7 +312,7 @@
         return c;
     }
 
-    // for use by CipherSuiteList only
+    // for use by SSLContextImpl only
     static Collection<CipherSuite> allowedCipherSuites() {
         return nameMap.values();
     }
@@ -372,7 +442,8 @@
     }
 
     static enum CipherType {
-        STREAM_CIPHER,         // null or stream cipher
+        NULL_CIPHER,           // null cipher
+        STREAM_CIPHER,         // stream cipher
         BLOCK_CIPHER,          // block cipher in CBC mode
         AEAD_CIPHER            // AEAD cipher
     }
@@ -387,7 +458,7 @@
     static enum BulkCipher {
 
         // export strength ciphers
-        B_NULL("NULL", STREAM_CIPHER, 0, 0, 0, 0, true),
+        B_NULL("NULL", NULL_CIPHER, 0, 0, 0, 0, true),
         B_RC4_40(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true),
         B_RC2_40("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false),
         B_DES_40(CIPHER_DES,  BLOCK_CIPHER, 5, 8, 8, 0, true),
@@ -568,7 +639,7 @@
                             iv = new IvParameterSpec(new byte[cipher.ivSize]);
                         }
                         temporary = cipher.newCipher(
-                                            ProtocolVersion.DEFAULT,
+                                            ProtocolVersion.DEFAULT_TLS,
                                             key, iv, secureRandom, true);
                         b = temporary.isAvailable();
                     } catch (NoSuchAlgorithmException e) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Ciphertext.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import static sun.security.ssl.HandshakeMessage.*;
+
+/*
+ * enumeration of record type
+ */
+final class Ciphertext {
+    final static Ciphertext CIPHERTEXT_NULL = new Ciphertext();
+
+    RecordType recordType;
+    long recordSN;
+
+    HandshakeStatus handshakeStatus;    // null if not used or not handshaking
+
+    Ciphertext() {
+        this.recordType = null;
+        this.recordSN = -1L;
+        this.handshakeStatus = null;
+    }
+
+    Ciphertext(RecordType recordType, long recordSN) {
+        this.recordType = recordType;
+        this.recordSN = recordSN;
+        this.handshakeStatus = null;
+    }
+
+    static enum RecordType {
+        RECORD_CHANGE_CIPHER_SPEC (
+                Record.ct_change_cipher_spec, ht_not_applicable),
+        RECORD_ALERT (
+                Record.ct_alert, ht_not_applicable),
+        RECORD_HELLO_REQUEST (
+                Record.ct_handshake, ht_hello_request),
+        RECORD_CLIENT_HELLO (
+                Record.ct_handshake, ht_client_hello),
+        RECORD_SERVER_HELLO (
+                Record.ct_handshake, ht_server_hello),
+        RECORD_HELLO_VERIFY_REQUEST (
+                Record.ct_handshake, ht_hello_verify_request),
+        RECORD_NEW_SESSION_TICKET (
+                Record.ct_handshake, ht_new_session_ticket),
+        RECORD_CERTIFICATE (
+                Record.ct_handshake, ht_certificate),
+        RECORD_SERVER_KEY_EXCHANGE (
+                Record.ct_handshake, ht_server_key_exchange),
+        RECORD_CERTIFICATE_REQUEST (
+                Record.ct_handshake, ht_certificate_request),
+        RECORD_SERVER_HELLO_DONE (
+                Record.ct_handshake, ht_server_hello_done),
+        RECORD_CERTIFICATE_VERIFY (
+                Record.ct_handshake, ht_certificate_verify),
+        RECORD_CLIENT_KEY_EXCHANGE (
+                Record.ct_handshake, ht_client_key_exchange),
+        RECORD_FINISHED (
+                Record.ct_handshake, ht_finished),
+        RECORD_CERTIFICATE_URL (
+                Record.ct_handshake, ht_certificate_url),
+        RECORD_CERTIFICATE_STATUS (
+                Record.ct_handshake, ht_certificate_status),
+        RECORD_SUPPLIEMENTAL_DATA (
+                Record.ct_handshake, ht_supplemental_data),
+        RECORD_APPLICATION_DATA (
+                Record.ct_application_data, ht_not_applicable);
+
+        byte contentType;
+        byte handshakeType;
+
+        private RecordType(byte contentType, byte handshakeType) {
+            this.contentType = contentType;
+            this.handshakeType = handshakeType;
+        }
+
+        static RecordType valueOf(byte contentType, byte handshakeType) {
+            if (contentType == Record.ct_change_cipher_spec) {
+                return RECORD_CHANGE_CIPHER_SPEC;
+            } else if (contentType == Record.ct_alert) {
+                return RECORD_ALERT;
+            } else if (contentType == Record.ct_application_data) {
+                return RECORD_APPLICATION_DATA;
+            } else if (handshakeType == ht_hello_request) {
+                return RECORD_HELLO_REQUEST;
+            } else if (handshakeType == ht_client_hello) {
+                return RECORD_CLIENT_HELLO;
+            } else if (handshakeType == ht_server_hello) {
+                return RECORD_SERVER_HELLO;
+            } else if (handshakeType == ht_hello_verify_request) {
+                return RECORD_HELLO_VERIFY_REQUEST;
+            } else if (handshakeType == ht_new_session_ticket) {
+                return RECORD_NEW_SESSION_TICKET;
+            } else if (handshakeType == ht_certificate) {
+                return RECORD_CERTIFICATE;
+            } else if (handshakeType == ht_server_key_exchange) {
+                return RECORD_SERVER_KEY_EXCHANGE;
+            } else if (handshakeType == ht_certificate_request) {
+                return RECORD_CERTIFICATE_REQUEST;
+            } else if (handshakeType == ht_server_hello_done) {
+                return RECORD_SERVER_HELLO_DONE;
+            } else if (handshakeType == ht_certificate_verify) {
+                return RECORD_CERTIFICATE_VERIFY;
+            } else if (handshakeType == ht_client_key_exchange) {
+                return RECORD_CLIENT_KEY_EXCHANGE;
+            } else if (handshakeType == ht_finished) {
+                return RECORD_FINISHED;
+            } else if (handshakeType == ht_certificate_url) {
+                return RECORD_CERTIFICATE_URL;
+            } else if (handshakeType == ht_certificate_status) {
+                return RECORD_CERTIFICATE_STATUS;
+            } else if (handshakeType == ht_supplemental_data) {
+                return RECORD_SUPPLIEMENTAL_DATA;
+            }
+
+            // otherwise, invalid record type
+            throw new IllegalArgumentException(
+                    "Invalid record type (ContentType:" + contentType +
+                    ", HandshakeType:" + handshakeType + ")");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientAuthType.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+/**
+ * Client authentication type.
+ */
+enum ClientAuthType {
+    CLIENT_AUTH_NONE,           // turn off client authentication
+    CLIENT_AUTH_REQUESTED,      // need to request client authentication
+    CLIENT_AUTH_REQUIRED        // require client authentication
+}
+
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Tue Jun 02 04:01:04 2015 +0000
@@ -141,11 +141,20 @@
     private final static boolean allowUnsafeServerCertChange =
         Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false);
 
+    // To switch off the max_fragment_length extension.
+    private final static boolean enableMFLExtension =
+            Debug.getBooleanProperty("jsse.enableMFLExtension", false);
+
     private List<SNIServerName> requestedServerNames =
             Collections.<SNIServerName>emptyList();
 
+    // maximum fragment length
+    private int requestedMFLength = -1;     // -1: no fragment length limit
+
     private boolean serverNamesAccepted = false;
 
+    private ClientHello initialClientHelloMsg = null;   // DTLS only
+
     /*
      * the reserved server certificate chain in previous handshaking
      *
@@ -172,11 +181,12 @@
             ProtocolList enabledProtocols,
             ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
-            byte[] clientVerifyData, byte[] serverVerifyData) {
+            byte[] clientVerifyData, byte[] serverVerifyData,
+            boolean isDTLS) {
 
         super(engine, context, enabledProtocols, true, true,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
-            clientVerifyData, serverVerifyData);
+            clientVerifyData, serverVerifyData, isDTLS);
     }
 
     /*
@@ -191,19 +201,35 @@
      */
     @Override
     void processMessage(byte type, int messageLen) throws IOException {
-        if (state >= type
-                && (type != HandshakeMessage.ht_hello_request)) {
-            throw new SSLProtocolException(
-                    "Handshake message sequence violation, " + type);
-        }
+        // check the handshake state
+        handshakeState.check(type);
 
         switch (type) {
         case HandshakeMessage.ht_hello_request:
-            this.serverHelloRequest(new HelloRequest(input));
+            HelloRequest helloRequest = new HelloRequest(input);
+            handshakeState.update(helloRequest, resumingSession);
+            this.serverHelloRequest(helloRequest);
+            break;
+
+        case HandshakeMessage.ht_hello_verify_request:
+            if (!isDTLS) {
+                throw new SSLProtocolException(
+                    "hello_verify_request is not a SSL/TLS handshake message");
+            }
+
+            HelloVerifyRequest helloVerifyRequest =
+                        new HelloVerifyRequest(input, messageLen);
+            handshakeState.update(helloVerifyRequest, resumingSession);
+            this.helloVerifyRequest(helloVerifyRequest);
             break;
 
         case HandshakeMessage.ht_server_hello:
-            this.serverHello(new ServerHello(input, messageLen));
+            ServerHello serverHello = new ServerHello(input, messageLen);
+            this.serverHello(serverHello);
+
+            // This handshake state update needs the resumingSession value
+            // set by serverHello().
+            handshakeState.update(serverHello, resumingSession);
             break;
 
         case HandshakeMessage.ht_certificate:
@@ -213,7 +239,9 @@
                     "unexpected server cert chain");
                 // NOTREACHED
             }
-            this.serverCertificate(new CertificateMsg(input));
+            CertificateMsg certificateMsg = new CertificateMsg(input);
+            handshakeState.update(certificateMsg, resumingSession);
+            this.serverCertificate(certificateMsg);
             serverKey =
                 session.getPeerCertificates()[0].getPublicKey();
             break;
@@ -249,41 +277,52 @@
                 }
 
                 try {
-                    this.serverKeyExchange(new RSA_ServerKeyExchange(input));
+                    RSA_ServerKeyExchange rsaSrvKeyExchange =
+                                    new RSA_ServerKeyExchange(input);
+                    handshakeState.update(rsaSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(rsaSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_DH_ANON:
                 try {
-                    this.serverKeyExchange(new DH_ServerKeyExchange(
-                                                input, protocolVersion));
+                    DH_ServerKeyExchange dhSrvKeyExchange =
+                            new DH_ServerKeyExchange(input, protocolVersion);
+                    handshakeState.update(dhSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(dhSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_DHE_DSS:
             case K_DHE_RSA:
                 try {
-                    this.serverKeyExchange(new DH_ServerKeyExchange(
-                        input, serverKey,
-                        clnt_random.random_bytes, svr_random.random_bytes,
-                        messageLen,
-                        localSupportedSignAlgs, protocolVersion));
+                    DH_ServerKeyExchange dhSrvKeyExchange =
+                        new DH_ServerKeyExchange(
+                            input, serverKey,
+                            clnt_random.random_bytes, svr_random.random_bytes,
+                            messageLen,
+                            localSupportedSignAlgs, protocolVersion);
+                    handshakeState.update(dhSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(dhSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_ECDHE_ECDSA:
             case K_ECDHE_RSA:
             case K_ECDH_ANON:
                 try {
-                    this.serverKeyExchange(new ECDH_ServerKeyExchange
-                        (input, serverKey, clnt_random.random_bytes,
-                        svr_random.random_bytes,
-                        localSupportedSignAlgs, protocolVersion));
+                    ECDH_ServerKeyExchange ecdhSrvKeyExchange =
+                        new ECDH_ServerKeyExchange
+                            (input, serverKey, clnt_random.random_bytes,
+                            svr_random.random_bytes,
+                            localSupportedSignAlgs, protocolVersion);
+                    handshakeState.update(ecdhSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(ecdhSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_RSA:
@@ -320,8 +359,9 @@
             if (debug != null && Debug.isOn("handshake")) {
                 certRequest.print(System.out);
             }
+            handshakeState.update(certRequest, resumingSession);
 
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 Collection<SignatureAndHashAlgorithm> peerSignAlgs =
                                         certRequest.getSignAlgorithms();
                 if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
@@ -345,33 +385,24 @@
             break;
 
         case HandshakeMessage.ht_server_hello_done:
-            this.serverHelloDone(new ServerHelloDone(input));
+            ServerHelloDone serverHelloDone = new ServerHelloDone(input);
+            handshakeState.update(serverHelloDone, resumingSession);
+            this.serverHelloDone(serverHelloDone);
+
             break;
 
         case HandshakeMessage.ht_finished:
-            // A ChangeCipherSpec record must have been received prior to
-            // reception of the Finished message (RFC 5246, 7.4.9).
-            if (!receivedChangeCipherSpec()) {
-                fatalSE(Alerts.alert_handshake_failure,
-                    "Received Finished message before ChangeCipherSpec");
-            }
+            Finished serverFinished =
+                    new Finished(protocolVersion, input, cipherSuite);
+            handshakeState.update(serverFinished, resumingSession);
+            this.serverFinished(serverFinished);
 
-            this.serverFinished(
-                new Finished(protocolVersion, input, cipherSuite));
             break;
 
         default:
             throw new SSLProtocolException(
                 "Illegal client handshake msg, " + type);
         }
-
-        //
-        // Move state machine forward if the message handling
-        // code didn't already do so
-        //
-        if (state < type) {
-            state = type;
-        }
     }
 
     /*
@@ -389,10 +420,10 @@
         // Could be (e.g. at connection setup) that we already
         // sent the "client hello" but the server's not seen it.
         //
-        if (state < HandshakeMessage.ht_client_hello) {
+        if (!clientHelloDelivered) {
             if (!secureRenegotiation && !allowUnsafeRenegotiation) {
                 // renegotiation is not allowed.
-                if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
+                if (activeProtocolVersion.useTLS10PlusSpec()) {
                     // response with a no_renegotiation warning,
                     warningSE(Alerts.alert_no_renegotiation);
 
@@ -428,6 +459,29 @@
         }
     }
 
+    private void helloVerifyRequest(
+            HelloVerifyRequest mesg) throws IOException {
+
+        if (debug != null && Debug.isOn("handshake")) {
+            mesg.print(System.out);
+        }
+
+        //
+        // Note that HelloVerifyRequest.server_version is used solely to
+        // indicate packet formatting, and not as part of version negotiation.
+        // Need not to check version values match for HelloVerifyRequest
+        // message.
+        //
+        initialClientHelloMsg.cookie = mesg.cookie.clone();
+
+        if (debug != null && Debug.isOn("handshake")) {
+            initialClientHelloMsg.print(System.out);
+        }
+
+        // deliver the ClientHello message with cookie
+        initialClientHelloMsg.write(output);
+        handshakeState.update(initialClientHelloMsg, resumingSession);
+    }
 
     /*
      * Server chooses session parameters given options created by the
@@ -441,6 +495,9 @@
      * probably authentication getting done.
      */
     private void serverHello(ServerHello mesg) throws IOException {
+        // Dispose the reserved ClientHello message (if exists).
+        initialClientHelloMsg = null;
+
         serverKeyExchangeReceived = false;
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
@@ -536,7 +593,7 @@
         }
 
         setCipherSuite(mesg.cipherSuite);
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
         }
 
@@ -611,9 +668,8 @@
                     }
                 }
 
-                // looks fine; resume it, and update the state machine.
+                // looks fine; resume it.
                 resumingSession = true;
-                state = HandshakeMessage.ht_finished - 1;
                 calculateConnectionKeys(session.getMasterSecret());
                 if (debug != null && Debug.isOn("session")) {
                     System.out.println("%% Server resumed " + session);
@@ -627,6 +683,24 @@
             }
         }
 
+        // check the "max_fragment_length" extension
+        MaxFragmentLengthExtension maxFragLenExt = (MaxFragmentLengthExtension)
+                mesg.extensions.get(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+        if (maxFragLenExt != null) {
+            if ((requestedMFLength == -1) ||
+                    maxFragLenExt.getMaxFragLen() != requestedMFLength) {
+                // If the client did not request this extension, or the
+                // response value is different from the length it requested,
+                // abort the handshake with a fatal illegal_parameter alert.
+                fatalSE(Alerts.alert_illegal_parameter,
+                        "Failed to negotiate the max_fragment_length");
+            }
+        } else if (!resumingSession) {
+            // no "max_fragment_length" extension
+            requestedMFLength = -1;
+        }   // Otherwise, using the value negotiated during the original
+            // session initiation
+
         if (resumingSession && session != null) {
             setHandshakeSessionSE(session);
             // Reserve the handshake state if this is a session-resumption
@@ -657,6 +731,8 @@
                             getLocalSupportedSignAlgs(),
                             mesg.sessionId, getHostSE(), getPortSE());
         session.setRequestedServerNames(requestedServerNames);
+        session.setNegotiatedMaxFragSize(requestedMFLength);
+        session.setMaximumPacketSize(maximumPacketSize);
         setHandshakeSessionSE(session);
         if (debug != null && Debug.isOn("handshake")) {
             System.out.println("** " + cipherSuite);
@@ -681,7 +757,6 @@
         ephemeralServerKey = mesg.getPublicKey();
     }
 
-
     /*
      * Diffie-Hellman key exchange.  We save the server public key and
      * our own D-H algorithm object so we can defer key calculations
@@ -716,13 +791,6 @@
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
         }
-        /*
-         * Always make sure the input has been digested before we
-         * start emitting data, to ensure the hashes are correctly
-         * computed for the Finished and CertificateVerify messages
-         * which we send (here).
-         */
-        input.digestNow();
 
         /*
          * FIRST ... if requested, send an appropriate Certificate chain
@@ -817,7 +885,7 @@
                 // server.  For SSLv3, send the no_certificate alert;
                 // TLS uses an empty cert chain instead.
                 //
-                if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+                if (protocolVersion.useTLS10PlusSpec()) {
                     m1 = new CertificateMsg(new X509Certificate [0]);
                 } else {
                     warningSE(Alerts.alert_no_certificate);
@@ -837,6 +905,7 @@
                     m1.print(System.out);
                 }
                 m1.write(output);
+                handshakeState.update(m1, resumingSession);
             }
         }
 
@@ -1000,7 +1069,7 @@
             m2.print(System.out);
         }
         m2.write(output);
-
+        handshakeState.update(m2, resumingSession);
 
         /*
          * THIRD, send a "change_cipher_spec" record followed by the
@@ -1010,8 +1079,6 @@
          * to compute the "Finished" message, and to compute the keys used
          * to protect all records following the change_cipher_spec.
          */
-
-        output.doHashes();
         output.flush();
 
         /*
@@ -1069,7 +1136,7 @@
             CertificateVerify m3;
             try {
                 SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     preferableSignatureAlgorithm =
                         SignatureAndHashAlgorithm.getPreferableAlgorithm(
                             peerSupportedSignAlgs, signingKey.getAlgorithm(),
@@ -1103,13 +1170,17 @@
                 m3.print(System.out);
             }
             m3.write(output);
-            output.doHashes();
+            handshakeState.update(m3, resumingSession);
+            output.flush();
         }
 
         /*
          * OK, that's that!
          */
         sendChangeCipherAndFinish(false);
+
+        // expecting the final ChangeCipherSpec and Finished messages
+        expectingFinishFlightSE();
     }
 
 
@@ -1158,8 +1229,9 @@
          * completed handshakes.
          */
         if (resumingSession) {
-            input.digestNow();
             sendChangeCipherAndFinish(true);
+        } else {
+            handshakeFinished = true;
         }
         session.setLastAccessedTime(System.currentTimeMillis());
 
@@ -1188,6 +1260,10 @@
      */
     private void sendChangeCipherAndFinish(boolean finishedTag)
             throws IOException {
+
+        // Reload if this message has been reserved.
+        handshakeHash.reload();
+
         Finished mesg = new Finished(protocolVersion, handshakeHash,
             Finished.CLIENT, session.getMasterSecret(), cipherSuite);
 
@@ -1205,13 +1281,6 @@
         if (secureRenegotiation) {
             clientVerifyData = mesg.getVerifyData();
         }
-
-        /*
-         * Update state machine so server MUST send 'finished' next.
-         * (In "long" handshake case; in short case, we're responding
-         * to its message.)
-         */
-        state = HandshakeMessage.ht_finished - 1;
     }
 
 
@@ -1361,10 +1430,10 @@
         // create the ClientHello message
         ClientHello clientHelloMessage = new ClientHello(
                 sslContext.getSecureRandom(), maxProtocolVersion,
-                sessionId, cipherSuites);
+                sessionId, cipherSuites, isDTLS);
 
         // add signature_algorithm extension
-        if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (maxProtocolVersion.useTLS12PlusSpec()) {
             // we will always send the signature_algorithm extension
             Collection<SignatureAndHashAlgorithm> localSignAlgs =
                                                 getLocalSupportedSignAlgs();
@@ -1389,6 +1458,37 @@
             }
         }
 
+        // add max_fragment_length extension
+        if (enableMFLExtension) {
+            if (session != null) {
+                // The same extension should be sent for resumption.
+                requestedMFLength = session.getNegotiatedMaxFragSize();
+            } else if (maximumPacketSize != 0) {
+                // Maybe we can calculate the fragment size more accurate
+                // by condering the enabled cipher suites in the future.
+                requestedMFLength = maximumPacketSize;
+                if (isDTLS) {
+                    requestedMFLength -= DTLSRecord.maxPlaintextPlusSize;
+                } else {
+                    requestedMFLength -= SSLRecord.maxPlaintextPlusSize;
+                }
+            } else {
+                // Need no max_fragment_length extension.
+                requestedMFLength = -1;
+            }
+
+            if ((requestedMFLength > 0) &&
+                MaxFragmentLengthExtension.needFragLenNego(requestedMFLength)) {
+
+                requestedMFLength =
+                        MaxFragmentLengthExtension.getValidMaxFragLen(
+                                                        requestedMFLength);
+                clientHelloMessage.addMFLExtension(requestedMFLength);
+            } else {
+                requestedMFLength = -1;
+            }
+        }
+
         // reset the client random cookie
         clnt_random = clientHelloMessage.clnt_random;
 
@@ -1403,6 +1503,11 @@
             clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData);
         }
 
+        if (isDTLS) {
+            // Cookie exchange need to reserve the initial ClientHello message.
+            initialClientHelloMsg = clientHelloMessage;
+        }
+
         return clientHelloMessage;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,1265 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+import javax.crypto.BadPaddingException;
+
+import javax.net.ssl.*;
+
+import sun.misc.HexDumpEncoder;
+import static sun.security.ssl.HandshakeMessage.*;
+
+/**
+ * DTLS {@code InputRecord} implementation for {@code SSLEngine}.
+ */
+final class DTLSInputRecord extends InputRecord implements DTLSRecord {
+
+    private DTLSReassembler reassembler = null;
+
+    // Cache the session identifier for the detection of session-resuming
+    // handshake.
+    byte[]              prevSessionID = new byte[0];
+
+    int                 readEpoch;
+
+    int                 prevReadEpoch;
+    Authenticator       prevReadAuthenticator;
+    CipherBox           prevReadCipher;
+
+    DTLSInputRecord() {
+        this.readEpoch = 0;
+        this.readAuthenticator = new MAC(true);
+
+        this.prevReadEpoch = 0;
+        this.prevReadCipher = CipherBox.NULL;
+        this.prevReadAuthenticator = new MAC(true);
+    }
+
+    @Override
+    void changeReadCiphers(Authenticator readAuthenticator,
+            CipherBox readCipher) {
+
+        prevReadCipher.dispose();
+
+        this.prevReadAuthenticator = this.readAuthenticator;
+        this.prevReadCipher = this.readCipher;
+        this.prevReadEpoch = this.readEpoch;
+
+        this.readAuthenticator = readAuthenticator;
+        this.readCipher = readCipher;
+        this.readEpoch++;
+    }
+
+    @Override
+    synchronized public void close() throws IOException {
+        if (!isClosed) {
+            prevReadCipher.dispose();
+            super.close();
+        }
+    }
+
+    @Override
+    boolean isEmpty() {
+        return ((reassembler == null) || reassembler.isEmpty());
+    }
+
+    @Override
+    int estimateFragmentSize(int packetSize) {
+        int macLen = 0;
+        if (readAuthenticator instanceof MAC) {
+            macLen = ((MAC)readAuthenticator).MAClen();
+        }
+
+        if (packetSize > 0) {
+            return readCipher.estimateFragmentSize(
+                    packetSize, macLen, headerSize);
+        } else {
+            return Record.maxDataSize;
+        }
+    }
+
+    @Override
+    void expectingFinishFlight() {
+        if (reassembler != null) {
+            reassembler.expectingFinishFlight();
+        }
+    }
+
+    @Override
+    Plaintext acquirePlaintext() {
+        if (reassembler != null) {
+            Plaintext plaintext = reassembler.acquirePlaintext();
+            if (reassembler.finished()) {
+                // discard all buffered unused message.
+                reassembler = null;
+            }
+
+            return plaintext;
+        }
+
+        return null;
+    }
+
+    @Override
+    Plaintext decode(ByteBuffer packet) {
+
+        if (isClosed) {
+            return null;
+        }
+
+        if (debug != null && Debug.isOn("packet")) {
+             Debug.printHex(
+                    "[Raw read]: length = " + packet.remaining(), packet);
+        }
+
+        // The caller should have validated the record.
+        int srcPos = packet.position();
+        int srcLim = packet.limit();
+
+        byte contentType = packet.get();                   // pos: 0
+        byte majorVersion = packet.get();                  // pos: 1
+        byte minorVersion = packet.get();                  // pos: 2
+        byte[] recordEnS = new byte[8];                    // epoch + seqence
+        packet.get(recordEnS);
+        int recordEpoch = ((recordEnS[0] & 0xFF) << 8) |
+                           (recordEnS[1] & 0xFF);          // pos: 3, 4
+        long recordSeq  = Authenticator.toLong(recordEnS);
+        int contentLen = ((packet.get() & 0xFF) << 8) |
+                          (packet.get() & 0xFF);            // pos: 11, 12
+
+        if (debug != null && Debug.isOn("record")) {
+             System.out.println(Thread.currentThread().getName() +
+                    ", READ: " +
+                    ProtocolVersion.valueOf(majorVersion, minorVersion) +
+                    " " + Record.contentName(contentType) + ", length = " +
+                    contentLen);
+        }
+
+        int recLim = srcPos + DTLSRecord.headerSize + contentLen;
+        if (this.readEpoch > recordEpoch) {
+            // Discard old records delivered before this epoch.
+
+            // Reset the position of the packet buffer.
+            packet.position(recLim);
+            return null;
+        }
+
+        if (this.readEpoch < recordEpoch) {
+            if (contentType != Record.ct_handshake) {
+                // just discard it if not a handshake message
+                packet.position(recLim);
+                return null;
+            }
+
+            // Not ready to decrypt this record, may be encrypted Finished
+            // message, need to buffer it.
+            if (reassembler == null) {
+               reassembler = new DTLSReassembler();
+            }
+
+            byte[] fragment = new byte[contentLen];
+            packet.get(fragment);              // copy the fragment
+            RecordFragment buffered = new RecordFragment(fragment, contentType,
+                    majorVersion, minorVersion,
+                    recordEnS, recordEpoch, recordSeq, true);
+
+            reassembler.queueUpFragment(buffered);
+
+            // consume the full record in the packet buffer.
+            packet.position(recLim);
+
+            Plaintext plaintext = reassembler.acquirePlaintext();
+            if (reassembler.finished()) {
+                // discard all buffered unused message.
+                reassembler = null;
+            }
+
+            return plaintext;
+        }
+
+        if (this.readEpoch == recordEpoch) {
+            // decrypt the fragment
+            packet.limit(recLim);
+            packet.position(srcPos + DTLSRecord.headerSize);
+
+            ByteBuffer plaintextFragment;
+            try {
+                plaintextFragment = decrypt(readAuthenticator,
+                        readCipher, contentType, packet, recordEnS);
+            } catch (BadPaddingException bpe) {
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                            " discard invalid record: " + bpe);
+                }
+
+                // invalid, discard this record [section 4.1.2.7, RFC 6347]
+                return null;
+            } finally {
+                // comsume a complete record
+                packet.limit(srcLim);
+                packet.position(recLim);
+            }
+
+            if (contentType != Record.ct_change_cipher_spec &&
+                contentType != Record.ct_handshake) {   // app data or alert
+                                                        // no retransmission
+               return new Plaintext(contentType, majorVersion, minorVersion,
+                        recordEpoch, recordSeq, plaintextFragment);
+            }
+
+            if (contentType == Record.ct_change_cipher_spec) {
+                if (reassembler == null) {
+                    // handshake has not started, should be an
+                    // old handshake message, discard it.
+                    return null;
+                }
+
+                reassembler.queueUpFragment(
+                        new RecordFragment(plaintextFragment, contentType,
+                                majorVersion, minorVersion,
+                                recordEnS, recordEpoch, recordSeq, false));
+            } else {    // handshake record
+                // One record may contain 1+ more handshake messages.
+                while (plaintextFragment.remaining() > 0) {
+
+                    HandshakeFragment hsFrag = parseHandshakeMessage(
+                        contentType, majorVersion, minorVersion,
+                        recordEnS, recordEpoch, recordSeq, plaintextFragment);
+
+                    if (hsFrag == null) {
+                        // invalid, discard this record
+                        return null;
+                    }
+
+                    if ((reassembler == null) &&
+                            isKickstart(hsFrag.handshakeType)) {
+                       reassembler = new DTLSReassembler();
+                    }
+
+                    if (reassembler != null) {
+                        reassembler.queueUpHandshake(hsFrag);
+                    }   // else, just ignore the message.
+                }
+            }
+
+            // Completed the read of the full record. Acquire the reassembled
+            // messages.
+            if (reassembler != null) {
+                Plaintext plaintext = reassembler.acquirePlaintext();
+                if (reassembler.finished()) {
+                    // discard all buffered unused message.
+                    reassembler = null;
+                }
+
+                return plaintext;
+            }
+        }
+
+        return null;    // make the complier happy
+    }
+
+    @Override
+    int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
+
+        // DTLS length field is in bytes 11/12
+        if (packet.remaining() < headerSize) {
+            return -1;
+        }
+
+        // Last sanity check that it's not a wild record
+        int pos = packet.position();
+
+        // Check the content type of the record.
+        byte contentType = packet.get(pos);
+        if (!Record.isValidContentType(contentType)) {
+            throw new SSLException(
+                    "Unrecognized SSL message, plaintext connection?");
+        }
+
+        // Check the protocol version of the record.
+        ProtocolVersion recordVersion =
+            ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2));
+        checkRecordVersion(recordVersion, false);
+
+        // Get the fragment length of the record.
+        int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) +
+                       (packet.get(pos + 12) & 0xFF) + headerSize;
+        if (fragLen > Record.maxFragmentSize) {
+            throw new SSLException(
+                    "Record overflow, fragment length (" + fragLen +
+                    ") MUST not exceed " + Record.maxFragmentSize);
+        }
+
+        return fragLen;
+    }
+
+    @Override
+    void checkRecordVersion(ProtocolVersion recordVersion,
+            boolean allowSSL20Hello) throws SSLException {
+
+        if (!recordVersion.maybeDTLSProtocol()) {
+            throw new SSLException(
+                    "Unrecognized record version " + recordVersion +
+                    " , plaintext connection?");
+        }
+    }
+
+    private static boolean isKickstart(byte handshakeType) {
+        return (handshakeType == HandshakeMessage.ht_client_hello) ||
+               (handshakeType == HandshakeMessage.ht_hello_request) ||
+               (handshakeType == HandshakeMessage.ht_hello_verify_request);
+    }
+
+    private static HandshakeFragment parseHandshakeMessage(
+            byte contentType, byte majorVersion, byte minorVersion,
+            byte[] recordEnS, int recordEpoch, long recordSeq,
+            ByteBuffer plaintextFragment) {
+
+        int remaining = plaintextFragment.remaining();
+        if (remaining < handshakeHeaderSize) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(
+                        Thread.currentThread().getName() +
+                        " discard invalid record: " +
+                        "too small record to hold a handshake fragment");
+            }
+
+            // invalid, discard this record [section 4.1.2.7, RFC 6347]
+            return null;
+        }
+
+        byte handshakeType = plaintextFragment.get();       // pos: 0
+        int messageLength =
+                ((plaintextFragment.get() & 0xFF) << 16) |
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 1-3
+        int messageSeq =
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 4/5
+        int fragmentOffset =
+                ((plaintextFragment.get() & 0xFF) << 16) |
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 6-8
+        int fragmentLength =
+                ((plaintextFragment.get() & 0xFF) << 16) |
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 9-11
+        if ((remaining - handshakeHeaderSize) < fragmentLength) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(
+                        Thread.currentThread().getName() +
+                        " discard invalid record: " +
+                        "not a complete handshake fragment in the record");
+            }
+
+            // invalid, discard this record [section 4.1.2.7, RFC 6347]
+            return null;
+        }
+
+        byte[] fragment = new byte[fragmentLength];
+        plaintextFragment.get(fragment);
+
+        return new HandshakeFragment(fragment, contentType,
+                majorVersion, minorVersion,
+                recordEnS, recordEpoch, recordSeq,
+                handshakeType, messageLength,
+                messageSeq, fragmentOffset, fragmentLength);
+    }
+
+    // buffered record fragment
+    private static class RecordFragment implements Comparable<RecordFragment> {
+        boolean         isCiphertext;
+
+        byte            contentType;
+        byte            majorVersion;
+        byte            minorVersion;
+        int             recordEpoch;
+        long            recordSeq;
+        byte[]          recordEnS;
+        byte[]          fragment;
+
+        RecordFragment(ByteBuffer fragBuf, byte contentType,
+                byte majorVersion, byte minorVersion, byte[] recordEnS,
+                int recordEpoch, long recordSeq, boolean isCiphertext) {
+            this((byte[])null, contentType, majorVersion, minorVersion,
+                    recordEnS, recordEpoch, recordSeq, isCiphertext);
+
+            this.fragment = new byte[fragBuf.remaining()];
+            fragBuf.get(this.fragment);
+        }
+
+        RecordFragment(byte[] fragment, byte contentType,
+                byte majorVersion, byte minorVersion, byte[] recordEnS,
+                int recordEpoch, long recordSeq, boolean isCiphertext) {
+            this.isCiphertext = isCiphertext;
+
+            this.contentType = contentType;
+            this.majorVersion = majorVersion;
+            this.minorVersion = minorVersion;
+            this.recordEpoch = recordEpoch;
+            this.recordSeq = recordSeq;
+            this.recordEnS = recordEnS;
+            this.fragment = fragment;       // The caller should have cloned
+                                            // the buffer if necessary.
+        }
+
+        @Override
+        public int compareTo(RecordFragment o) {
+            return Long.compareUnsigned(this.recordSeq, o.recordSeq);
+        }
+    }
+
+    // buffered handshake message
+    private static final class HandshakeFragment extends RecordFragment {
+
+        byte            handshakeType;     // handshake msg_type
+        int             messageSeq;        // message_seq
+        int             messageLength;     // Handshake body length
+        int             fragmentOffset;    // fragment_offset
+        int             fragmentLength;    // fragment_length
+
+        HandshakeFragment(byte[] fragment, byte contentType,
+                byte majorVersion, byte minorVersion, byte[] recordEnS,
+                int recordEpoch, long recordSeq,
+                byte handshakeType, int messageLength,
+                int messageSeq, int fragmentOffset, int fragmentLength) {
+
+            super(fragment, contentType, majorVersion, minorVersion,
+                    recordEnS, recordEpoch , recordSeq, false);
+
+            this.handshakeType = handshakeType;
+            this.messageSeq = messageSeq;
+            this.messageLength = messageLength;
+            this.fragmentOffset = fragmentOffset;
+            this.fragmentLength = fragmentLength;
+        }
+
+        @Override
+        public int compareTo(RecordFragment o) {
+            if (o instanceof HandshakeFragment) {
+                HandshakeFragment other = (HandshakeFragment)o;
+                if (this.messageSeq != other.messageSeq) {
+                    // keep the insertion order for the same message
+                    return this.messageSeq - other.messageSeq;
+                }
+            }
+
+            return Long.compareUnsigned(this.recordSeq, o.recordSeq);
+        }
+    }
+
+    private static final class HoleDescriptor {
+        int offset;             // fragment_offset
+        int limit;              // fragment_offset + fragment_length
+
+        HoleDescriptor(int offset, int limit) {
+            this.offset = offset;
+            this.limit = limit;
+        }
+    }
+
+    final class DTLSReassembler {
+        TreeSet<RecordFragment> bufferedFragments = new TreeSet<>();
+
+        HashMap<Byte, List<HoleDescriptor>> holesMap = new HashMap<>(5);
+
+        // Epoch, sequence number and handshake message sequence of the
+        // beginning message of a flight.
+        byte        flightType = (byte)0xFF;
+
+        int         flightTopEpoch = 0;
+        long        flightTopRecordSeq = -1;
+        int         flightTopMessageSeq = 0;
+
+        // Epoch, sequence number and handshake message sequence of the
+        // next message acquisition of a flight.
+        int         nextRecordEpoch = 0;    // next record epoch
+        long        nextRecordSeq = 0;      // next record sequence number
+        int         nextMessageSeq = 0;     // next handshake message number
+
+        // Expect ChangeCipherSpec and Finished messages for the final flight.
+        boolean     expectCCSFlight = false;
+
+        // Ready to process this flight if received all messages of the flight.
+        boolean     flightIsReady = false;
+        boolean     needToCheckFlight = false;
+
+        // Is it a session-resuming abbreviated handshake.?
+        boolean     isAbbreviatedHandshake = false;
+
+        // The handshke fragment with the biggest record sequence number
+        // in a flight, not counting the Finished message.
+        HandshakeFragment lastHandshakeFragment = null;
+
+        // Is handshake (intput) finished?
+        boolean handshakeFinished = false;
+
+        DTLSReassembler() {
+            // blank
+        }
+
+        boolean finished() {
+            return handshakeFinished;
+        }
+
+        void expectingFinishFlight() {
+            expectCCSFlight = true;
+        }
+
+        void queueUpHandshake(HandshakeFragment hsf) {
+
+            if ((nextRecordEpoch > hsf.recordEpoch) ||
+                    (nextRecordSeq > hsf.recordSeq) ||
+                    (nextMessageSeq > hsf.messageSeq)) {
+                // too old, discard this record
+                return;
+            }
+
+            // Is it the first message of next flight?
+            if ((flightTopMessageSeq == hsf.messageSeq) &&
+                    (hsf.fragmentOffset == 0) && (flightTopRecordSeq == -1)) {
+
+                flightType = hsf.handshakeType;
+                flightTopEpoch = hsf.recordEpoch;
+                flightTopRecordSeq = hsf.recordSeq;
+
+                if (hsf.handshakeType == HandshakeMessage.ht_server_hello) {
+                    // Is it a session-resuming handshake?
+                    try {
+                        isAbbreviatedHandshake =
+                                isSessionResuming(hsf.fragment, prevSessionID);
+                    } catch (SSLException ssle) {
+                        if (debug != null && Debug.isOn("ssl")) {
+                            System.out.println(
+                                    Thread.currentThread().getName() +
+                                    " discard invalid record: " + ssle);
+                        }
+
+                        // invalid, discard it [section 4.1.2.7, RFC 6347]
+                        return;
+                    }
+
+                    if (!isAbbreviatedHandshake) {
+                        prevSessionID = getSessionID(hsf.fragment);
+                    }
+                }
+            }
+
+            boolean fragmented = false;
+            if ((hsf.fragmentOffset) != 0 ||
+                (hsf.fragmentLength != hsf.messageLength)) {
+
+                fragmented = true;
+            }
+
+            List<HoleDescriptor> holes = holesMap.get(hsf.handshakeType);
+            if (holes == null) {
+                if (!fragmented) {
+                    holes = Collections.emptyList();
+                } else {
+                    holes = new LinkedList<HoleDescriptor>();
+                    holes.add(new HoleDescriptor(0, hsf.messageLength));
+                }
+                holesMap.put(hsf.handshakeType, holes);
+            } else if (holes.isEmpty()) {
+                // Have got the full handshake message.  This record may be
+                // a handshake message retransmission.  Discard this record.
+                //
+                // It's OK to discard retransmission as the handshake hash
+                // is computed as if each handshake message had been sent
+                // as a single fragment.
+                //
+                // Note that ClientHello messages are delivered twice in
+                // DTLS handshaking.
+                if ((hsf.handshakeType != HandshakeMessage.ht_client_hello &&
+                     hsf.handshakeType != ht_hello_verify_request) ||
+                        (nextMessageSeq != hsf.messageSeq)) {
+                    return;
+                }
+
+                if (fragmented) {
+                    holes = new LinkedList<HoleDescriptor>();
+                    holes.add(new HoleDescriptor(0, hsf.messageLength));
+                }
+                holesMap.put(hsf.handshakeType, holes);
+            }
+
+            if (fragmented) {
+                int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength;
+                for (int i = 0; i < holes.size(); i++) {
+
+                    HoleDescriptor hole = holes.get(i);
+                    if ((hole.limit <= hsf.fragmentOffset) ||
+                        (hole.offset >= fragmentLimit)) {
+                        // Also discard overlapping handshake retransmissions.
+                        continue;
+                    }
+
+                    // The ranges SHOULD NOT overlap.
+                    if (((hole.offset > hsf.fragmentOffset) &&
+                         (hole.offset < fragmentLimit)) ||
+                        ((hole.limit > hsf.fragmentOffset) &&
+                         (hole.limit < fragmentLimit))) {
+
+                        if (debug != null && Debug.isOn("ssl")) {
+                            System.out.println(
+                                Thread.currentThread().getName() +
+                                " discard invalid record: " +
+                                "handshake fragment ranges are overlapping");
+                        }
+
+                        // invalid, discard it [section 4.1.2.7, RFC 6347]
+                        return;
+                    }
+
+                    // This record interacts with this hole, fill the hole.
+                    holes.remove(i);
+                    // i--;
+
+                    if (hsf.fragmentOffset > hole.offset) {
+                        holes.add(new HoleDescriptor(
+                                hole.offset, hsf.fragmentOffset));
+                        // i++;
+                    }
+
+                    if (fragmentLimit < hole.limit) {
+                        holes.add(new HoleDescriptor(
+                                fragmentLimit, hole.limit));
+                        // i++;
+                    }
+
+                    // As no ranges overlap, no interact with other holes.
+                    break;
+                }
+            }
+
+            // append this fragment
+            bufferedFragments.add(hsf);
+
+            if ((lastHandshakeFragment == null) ||
+                (lastHandshakeFragment.compareTo(hsf) < 0)) {
+
+                lastHandshakeFragment = hsf;
+            }
+
+            if (flightIsReady) {
+                flightIsReady = false;
+            }
+            needToCheckFlight = true;
+        }
+
+        // queue up change_cipher_spec or encrypted message
+        void queueUpFragment(RecordFragment rf) {
+            if ((nextRecordEpoch > rf.recordEpoch) ||
+                    (nextRecordSeq > rf.recordSeq)) {
+                // too old, discard this record
+                return;
+            }
+
+            // Is it the first message of next flight?
+            if (expectCCSFlight &&
+                    (rf.contentType == Record.ct_change_cipher_spec)) {
+
+                flightType = (byte)0xFE;
+                flightTopEpoch = rf.recordEpoch;
+                flightTopRecordSeq = rf.recordSeq;
+            }
+
+            // append this fragment
+            bufferedFragments.add(rf);
+
+            if (flightIsReady) {
+                flightIsReady = false;
+            }
+            needToCheckFlight = true;
+        }
+
+        boolean isEmpty() {
+            return (bufferedFragments.isEmpty() ||
+                    (!flightIsReady && !needToCheckFlight) ||
+                    (needToCheckFlight && !flightIsReady()));
+        }
+
+        Plaintext acquirePlaintext() {
+            if (bufferedFragments.isEmpty()) {
+                // reset the flight
+                if (flightIsReady) {
+                    flightIsReady = false;
+                    needToCheckFlight = false;
+                }
+
+                return null;
+            }
+
+            if (!flightIsReady && needToCheckFlight) {
+                // check the fligth status
+                flightIsReady = flightIsReady();
+
+                // set for next flight
+                if (flightIsReady) {
+                    flightTopMessageSeq = lastHandshakeFragment.messageSeq + 1;
+                    flightTopRecordSeq = -1;
+                }
+
+                needToCheckFlight = false;
+            }
+
+            if (!flightIsReady) {
+                return null;
+            }
+
+            RecordFragment rFrag = bufferedFragments.first();
+            if (!rFrag.isCiphertext) {
+                // handshake message, or ChangeCipherSpec message
+                return acquireHandshakeMessage();
+            } else {
+                // a Finished message or other ciphertexts
+                return acquireCachedMessage();
+            }
+        }
+
+        private Plaintext acquireCachedMessage() {
+
+            RecordFragment rFrag = bufferedFragments.first();
+            if (readEpoch != rFrag.recordEpoch) {
+                if (readEpoch > rFrag.recordEpoch) {
+                    // discard old records
+                    bufferedFragments.remove(rFrag);    // popup the fragment
+                }
+
+                // reset the flight
+                if (flightIsReady) {
+                    flightIsReady = false;
+                }
+                return null;
+            }
+
+            bufferedFragments.remove(rFrag);    // popup the fragment
+
+            ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment);
+            ByteBuffer plaintextFragment = null;
+            try {
+                plaintextFragment = decrypt(readAuthenticator, readCipher,
+                        rFrag.contentType, fragment, rFrag.recordEnS);
+            } catch (BadPaddingException bpe) {
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                            " discard invalid record: " + bpe);
+                }
+
+                // invalid, discard this record [section 4.1.2.7, RFC 6347]
+                return null;
+            }
+
+            // The ciphtext handshake message can only be Finished (the
+            // end of this flight), ClinetHello or HelloRequest (the
+            // beginning of the next flight) message.  Need not to check
+            // any ChangeCipherSpec message.
+            if (rFrag.contentType == Record.ct_handshake) {
+                HandshakeFragment finFrag = null;
+                while (plaintextFragment.remaining() > 0) {
+                    HandshakeFragment hsFrag = parseHandshakeMessage(
+                            rFrag.contentType,
+                            rFrag.majorVersion, rFrag.minorVersion,
+                            rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq,
+                            plaintextFragment);
+
+                    if (hsFrag == null) {
+                        // invalid, discard this record
+                        return null;
+                    }
+
+                    if (hsFrag.handshakeType == HandshakeMessage.ht_finished) {
+                        finFrag = hsFrag;
+
+                        // reset for the next flight
+                        this.flightType = (byte)0xFF;
+                        this.flightTopEpoch = rFrag.recordEpoch;
+                        this.flightTopMessageSeq = hsFrag.messageSeq + 1;
+                        this.flightTopRecordSeq = -1;
+                    } else {
+                        // reset the flight
+                        if (flightIsReady) {
+                            flightIsReady = false;
+                        }
+                        queueUpHandshake(hsFrag);
+                    }
+                }
+
+                this.nextRecordSeq = rFrag.recordSeq + 1;
+                this.nextMessageSeq = 0;
+
+                if (finFrag != null) {
+                    this.nextRecordEpoch = finFrag.recordEpoch;
+                    this.nextRecordSeq = finFrag.recordSeq + 1;
+                    this.nextMessageSeq = finFrag.messageSeq + 1;
+
+                    // Finished message does not fragment.
+                    byte[] recordFrag = new byte[finFrag.messageLength + 4];
+                    Plaintext plaintext = new Plaintext(finFrag.contentType,
+                            finFrag.majorVersion, finFrag.minorVersion,
+                            finFrag.recordEpoch, finFrag.recordSeq,
+                            ByteBuffer.wrap(recordFrag));
+
+                    // fill the handshake fragment of the record
+                    recordFrag[0] = finFrag.handshakeType;
+                    recordFrag[1] =
+                            (byte)((finFrag.messageLength >>> 16) & 0xFF);
+                    recordFrag[2] =
+                            (byte)((finFrag.messageLength >>> 8) & 0xFF);
+                    recordFrag[3] = (byte)(finFrag.messageLength & 0xFF);
+
+                    System.arraycopy(finFrag.fragment, 0,
+                            recordFrag, 4, finFrag.fragmentLength);
+
+                    // handshake hashing
+                    handshakeHashing(finFrag, plaintext);
+
+                    // input handshake finished
+                    handshakeFinished = true;
+
+                    return plaintext;
+                } else {
+                    return acquirePlaintext();
+                }
+            } else {
+                return new Plaintext(rFrag.contentType,
+                        rFrag.majorVersion, rFrag.minorVersion,
+                        rFrag.recordEpoch, rFrag.recordSeq,
+                        plaintextFragment);
+            }
+        }
+
+        private Plaintext acquireHandshakeMessage() {
+
+            RecordFragment rFrag = bufferedFragments.first();
+            if (rFrag.contentType == Record.ct_change_cipher_spec) {
+                this.nextRecordEpoch = rFrag.recordEpoch + 1;
+                this.nextRecordSeq = 0;
+                // no change on next handshake message sequence number
+
+                bufferedFragments.remove(rFrag);        // popup the fragment
+
+                // Reload if this message has been reserved for handshake hash.
+                handshakeHash.reload();
+
+                return new Plaintext(rFrag.contentType,
+                        rFrag.majorVersion, rFrag.minorVersion,
+                        rFrag.recordEpoch, rFrag.recordSeq,
+                        ByteBuffer.wrap(rFrag.fragment));
+            } else {    // rFrag.contentType == Record.ct_handshake
+                HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
+                if ((hsFrag.messageLength == hsFrag.fragmentLength) &&
+                    (hsFrag.fragmentOffset == 0)) {     // no fragmentation
+
+                    bufferedFragments.remove(rFrag);    // popup the fragment
+
+                    // this.nextRecordEpoch = hsFrag.recordEpoch;
+                    this.nextRecordSeq = hsFrag.recordSeq + 1;
+                    this.nextMessageSeq = hsFrag.messageSeq + 1;
+
+                    // Note: may try to avoid byte array copy in the future.
+                    byte[] recordFrag = new byte[hsFrag.messageLength + 4];
+                    Plaintext plaintext = new Plaintext(hsFrag.contentType,
+                            hsFrag.majorVersion, hsFrag.minorVersion,
+                            hsFrag.recordEpoch, hsFrag.recordSeq,
+                            ByteBuffer.wrap(recordFrag));
+
+                    // fill the handshake fragment of the record
+                    recordFrag[0] = hsFrag.handshakeType;
+                    recordFrag[1] =
+                            (byte)((hsFrag.messageLength >>> 16) & 0xFF);
+                    recordFrag[2] =
+                            (byte)((hsFrag.messageLength >>> 8) & 0xFF);
+                    recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
+
+                    System.arraycopy(hsFrag.fragment, 0,
+                            recordFrag, 4, hsFrag.fragmentLength);
+
+                    // handshake hashing
+                    handshakeHashing(hsFrag, plaintext);
+
+                    return plaintext;
+                } else {                // fragmented handshake message
+                    // the first record
+                    //
+                    // Note: may try to avoid byte array copy in the future.
+                    byte[] recordFrag = new byte[hsFrag.messageLength + 4];
+                    Plaintext plaintext = new Plaintext(hsFrag.contentType,
+                            hsFrag.majorVersion, hsFrag.minorVersion,
+                            hsFrag.recordEpoch, hsFrag.recordSeq,
+                            ByteBuffer.wrap(recordFrag));
+
+                    // fill the handshake fragment of the record
+                    recordFrag[0] = hsFrag.handshakeType;
+                    recordFrag[1] =
+                            (byte)((hsFrag.messageLength >>> 16) & 0xFF);
+                    recordFrag[2] =
+                            (byte)((hsFrag.messageLength >>> 8) & 0xFF);
+                    recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
+
+                    int msgSeq = hsFrag.messageSeq;
+                    long maxRecodeSN = hsFrag.recordSeq;
+                    HandshakeFragment hmFrag = hsFrag;
+                    do {
+                        System.arraycopy(hmFrag.fragment, 0,
+                                recordFrag, hmFrag.fragmentOffset + 4,
+                                hmFrag.fragmentLength);
+                        // popup the fragment
+                        bufferedFragments.remove(rFrag);
+
+                        if (maxRecodeSN < hmFrag.recordSeq) {
+                            maxRecodeSN = hmFrag.recordSeq;
+                        }
+
+                        // Note: may buffer retransmitted fragments in order to
+                        // speed up the reassembly in the future.
+
+                        // read the next buffered record
+                        if (!bufferedFragments.isEmpty()) {
+                            rFrag = bufferedFragments.first();
+                            if (rFrag.contentType != Record.ct_handshake) {
+                                break;
+                            } else {
+                                hmFrag = (HandshakeFragment)rFrag;
+                            }
+                        }
+                    } while (!bufferedFragments.isEmpty() &&
+                            (msgSeq == hmFrag.messageSeq));
+
+                    // handshake hashing
+                    handshakeHashing(hsFrag, plaintext);
+
+                    this.nextRecordSeq = maxRecodeSN + 1;
+                    this.nextMessageSeq = msgSeq + 1;
+
+                    return plaintext;
+                }
+            }
+        }
+
+        boolean flightIsReady() {
+
+            //
+            // the ChangeCipherSpec/Finished flight
+            //
+            if (expectCCSFlight) {
+                // Have the ChangeCipherSpec/Finished messages been received?
+                return hasFinisedMessage(bufferedFragments);
+            }
+
+            if (flightType == (byte)0xFF) {
+                return false;
+            }
+
+            if ((flightType == HandshakeMessage.ht_client_hello) ||
+                (flightType == HandshakeMessage.ht_hello_request) ||
+                (flightType == HandshakeMessage.ht_hello_verify_request)) {
+
+                // single handshake message flight
+                return hasCompleted(holesMap.get(flightType));
+            }
+
+            //
+            // the ServerHello flight
+            //
+            if (flightType == HandshakeMessage.ht_server_hello) {
+                // Firstly, check the first flight handshake message.
+                if (!hasCompleted(holesMap.get(flightType))) {
+                    return false;
+                }
+
+                //
+                // an abbreviated handshake
+                //
+                if (isAbbreviatedHandshake) {
+                    // Ready to use the flight if received the
+                    // ChangeCipherSpec and Finished messages.
+                    return hasFinisedMessage(bufferedFragments);
+                }
+
+                //
+                // a full handshake
+                //
+                if (lastHandshakeFragment.handshakeType !=
+                        HandshakeMessage.ht_server_hello_done) {
+                    // Not yet got the final message of the flight.
+                    return false;
+                }
+
+                // Have all handshake message been received?
+                return hasCompleted(bufferedFragments,
+                    flightTopMessageSeq, lastHandshakeFragment.messageSeq);
+            }
+
+            //
+            // the ClientKeyExchange flight
+            //
+            // Note: need to consider more messages in this flight if
+            //       ht_supplemental_data and ht_certificate_url are
+            //       suppported in the future.
+            //
+            if ((flightType == HandshakeMessage.ht_certificate) ||
+                (flightType == HandshakeMessage.ht_client_key_exchange)) {
+
+                // Firstly, check the first flight handshake message.
+                if (!hasCompleted(holesMap.get(flightType))) {
+                    return false;
+                }
+
+                if (!hasFinisedMessage(bufferedFragments)) {
+                    // not yet got the ChangeCipherSpec/Finished messages
+                    return false;
+                }
+
+                if (flightType == HandshakeMessage.ht_client_key_exchange) {
+                    // single handshake message flight
+                    return true;
+                }
+
+                //
+                // flightType == HandshakeMessage.ht_certificate
+                //
+                // We don't support certificates containing fixed
+                // Diffie-Hellman parameters.  Therefore, CertificateVerify
+                // message is required if client Certificate message presents.
+                //
+                if (lastHandshakeFragment.handshakeType !=
+                        HandshakeMessage.ht_certificate_verify) {
+                    // Not yet got the final message of the flight.
+                    return false;
+                }
+
+                // Have all handshake message been received?
+                return hasCompleted(bufferedFragments,
+                    flightTopMessageSeq, lastHandshakeFragment.messageSeq);
+            }
+
+            //
+            // Otherwise, need to receive more handshake messages.
+            //
+            return false;
+        }
+
+        private boolean isSessionResuming(
+                byte[] fragment, byte[] prevSid) throws SSLException {
+
+            // As the first fragment of ServerHello should be big enough
+            // to hold the session_id field, need not to worry about the
+            // fragmentation here.
+            if ((fragment == null) || (fragment.length < 38)) {
+                                    // 38: the minimal ServerHello body length
+                throw new SSLException(
+                        "Invalid ServerHello message: no sufficient data");
+            }
+
+            int sidLen = fragment[34];          // 34: the length field
+            if (sidLen > 32) {                  // opaque SessionID<0..32>
+                throw new SSLException(
+                        "Invalid ServerHello message: invalid session id");
+            }
+
+            if (fragment.length < 38 + sidLen) {
+                throw new SSLException(
+                        "Invalid ServerHello message: no sufficient data");
+            }
+
+            if (sidLen != 0 && (prevSid.length == sidLen)) {
+                // may be a session-resuming handshake
+                for (int i = 0; i < sidLen; i++) {
+                    if (prevSid[i] != fragment[35 + i]) {
+                                                // 35: the session identifier
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        private byte[] getSessionID(byte[] fragment) {
+            // The validity has been checked in the call to isSessionResuming().
+            int sidLen = fragment[34];      // 34: the sessionID length field
+
+            byte[] temporary = new byte[sidLen];
+            System.arraycopy(fragment, 35, temporary, 0, sidLen);
+
+            return temporary;
+        }
+
+        // Looking for the ChangeCipherSpec and Finished messages.
+        //
+        // As the cached Finished message should be a ciphertext, we don't
+        // exactly know a ciphertext is a Finished message or not.  According
+        // to the spec of TLS/DTLS handshaking, a Finished message is always
+        // sent immediately after a ChangeCipherSpec message.  The first
+        // ciphertext handshake message should be the expected Finished message.
+        private boolean hasFinisedMessage(
+                Set<RecordFragment> fragments) {
+
+            boolean hasCCS = false;
+            boolean hasFin = false;
+            for (RecordFragment fragment : fragments) {
+                if (fragment.contentType == Record.ct_change_cipher_spec) {
+                    if (hasFin) {
+                        return true;
+                    }
+                    hasCCS = true;
+                } else if (fragment.contentType == Record.ct_handshake) {
+                    // Finished is the first expected message of a new epoch.
+                    if (fragment.isCiphertext) {
+                        if (hasCCS) {
+                            return true;
+                        }
+                        hasFin = true;
+                    }
+                }
+            }
+
+            return hasFin && hasCCS;
+        }
+
+        private boolean hasCompleted(List<HoleDescriptor> holes) {
+            if (holes == null) {
+                // not yet received this kind of handshake message
+                return false;
+            }
+
+            return holes.isEmpty();  // no fragment hole for complete message
+        }
+
+        private boolean hasCompleted(
+                Set<RecordFragment> fragments,
+                int presentMsgSeq, int endMsgSeq) {
+
+            // The caller should have checked the completion of the first
+            // present handshake message.  Need not to check it again.
+            for (RecordFragment rFrag : fragments) {
+                if ((rFrag.contentType != Record.ct_handshake) ||
+                        rFrag.isCiphertext) {
+                    break;
+                }
+
+                HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
+                if (hsFrag.messageSeq == presentMsgSeq) {
+                    continue;
+                } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) {
+                    // check the completion of the handshake message
+                    if (!hasCompleted(holesMap.get(hsFrag.handshakeType))) {
+                        return false;
+                    }
+
+                    presentMsgSeq = hsFrag.messageSeq;
+                } else {
+                    // not yet got handshake message next to presentMsgSeq
+                    break;
+                }
+            }
+
+            return (presentMsgSeq >= endMsgSeq);
+                        // false: if not yet got all messages of the flight.
+        }
+
+        private void handshakeHashing(
+                HandshakeFragment hsFrag, Plaintext plaintext) {
+
+            byte hsType = hsFrag.handshakeType;
+            if ((hsType == HandshakeMessage.ht_hello_request) ||
+                (hsType == HandshakeMessage.ht_hello_verify_request)) {
+
+                // omitted from handshake hash computation
+                return;
+            }
+
+            if ((hsFrag.messageSeq == 0) &&
+                (hsType == HandshakeMessage.ht_client_hello)) {
+
+                // omit initial ClientHello message
+                //
+                //  4: handshake header
+                //  2: ClientHello.client_version
+                // 32: ClientHello.random
+                int sidLen = plaintext.fragment.get(38);
+
+                if (sidLen == 0) {      // empty session_id, initial handshake
+                    return;
+                }
+            }
+
+            // calculate the DTLS header
+            byte[] temporary = new byte[12];    // 12: handshake header size
+
+            // Handshake.msg_type
+            temporary[0] = hsFrag.handshakeType;
+
+            // Handshake.length
+            temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF);
+            temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF);
+            temporary[3] = (byte)(hsFrag.messageLength & 0xFF);
+
+            // Handshake.message_seq
+            temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF);
+            temporary[5] = (byte)(hsFrag.messageSeq & 0xFF);
+
+            // Handshake.fragment_offset
+            temporary[6] = 0;
+            temporary[7] = 0;
+            temporary[8] = 0;
+
+            // Handshake.fragment_length
+            temporary[9] = temporary[1];
+            temporary[10] = temporary[2];
+            temporary[11] = temporary[3];
+
+            plaintext.fragment.position(4);     // ignore the TLS header
+            if ((hsType != HandshakeMessage.ht_finished) &&
+                (hsType != HandshakeMessage.ht_certificate_verify)) {
+
+                if (handshakeHash == null) {
+                    // used for cache only
+                    handshakeHash = new HandshakeHash(false);
+                }
+                handshakeHash.update(temporary, 0, 12);
+                handshakeHash.update(plaintext.fragment);
+            } else {
+                // Reserve until this handshake message has been processed.
+                if (handshakeHash == null) {
+                    // used for cache only
+                    handshakeHash = new HandshakeHash(false);
+                }
+                handshakeHash.reserve(temporary, 0, 12);
+                handshakeHash.reserve(plaintext.fragment);
+            }
+            plaintext.fragment.position(0);     // restore the position
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+
+import javax.crypto.BadPaddingException;
+
+import javax.net.ssl.*;
+
+import sun.misc.HexDumpEncoder;
+import static sun.security.ssl.Ciphertext.RecordType;
+
+/**
+ * DTLS {@code OutputRecord} implementation for {@code SSLEngine}.
+ */
+final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
+
+    private DTLSFragmenter fragmenter = null;
+
+    int                 writeEpoch;
+
+    int                 prevWriteEpoch;
+    Authenticator       prevWriteAuthenticator;
+    CipherBox           prevWriteCipher;
+
+    private LinkedList<RecordMemo> alertMemos = new LinkedList<>();
+
+    DTLSOutputRecord() {
+        this.writeAuthenticator = new MAC(true);
+
+        this.writeEpoch = 0;
+        this.prevWriteEpoch = 0;
+        this.prevWriteCipher = CipherBox.NULL;
+        this.prevWriteAuthenticator = new MAC(true);
+
+        this.packetSize = DTLSRecord.maxRecordSize;
+        this.protocolVersion = ProtocolVersion.DEFAULT_DTLS;
+    }
+
+    @Override
+    void changeWriteCiphers(Authenticator writeAuthenticator,
+            CipherBox writeCipher) throws IOException {
+
+        encodeChangeCipherSpec();
+
+        prevWriteCipher.dispose();
+
+        this.prevWriteAuthenticator = this.writeAuthenticator;
+        this.prevWriteCipher = this.writeCipher;
+        this.prevWriteEpoch = this.writeEpoch;
+
+        this.writeAuthenticator = writeAuthenticator;
+        this.writeCipher = writeCipher;
+        this.writeEpoch++;
+
+        this.isFirstAppOutputRecord = true;
+
+        // set the epoch number
+        this.writeAuthenticator.setEpochNumber(this.writeEpoch);
+    }
+
+    @Override
+    void encodeAlert(byte level, byte description) throws IOException {
+        RecordMemo memo = new RecordMemo();
+
+        memo.contentType = Record.ct_alert;
+        memo.majorVersion = protocolVersion.major;
+        memo.minorVersion = protocolVersion.minor;
+        memo.encodeEpoch = writeEpoch;
+        memo.encodeCipher = writeCipher;
+        memo.encodeAuthenticator = writeAuthenticator;
+
+        memo.fragment = new byte[2];
+        memo.fragment[0] = level;
+        memo.fragment[1] = description;
+
+        alertMemos.add(memo);
+    }
+
+    @Override
+    void encodeChangeCipherSpec() throws IOException {
+        if (fragmenter == null) {
+           fragmenter = new DTLSFragmenter();
+        }
+        fragmenter.queueUpChangeCipherSpec();
+    }
+
+    @Override
+    void encodeHandshake(byte[] source,
+            int offset, int length) throws IOException {
+
+        if (firstMessage) {
+            firstMessage = false;
+        }
+
+        if (fragmenter == null) {
+           fragmenter = new DTLSFragmenter();
+        }
+
+        fragmenter.queueUpHandshake(source, offset, length);
+    }
+
+    @Override
+    Ciphertext encode(ByteBuffer[] sources, int offset, int length,
+            ByteBuffer destination) throws IOException {
+
+        if (writeAuthenticator.seqNumOverflow()) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(Thread.currentThread().getName() +
+                    ", sequence number extremely close to overflow " +
+                    "(2^64-1 packets). Closing connection.");
+            }
+
+            throw new SSLHandshakeException("sequence number overflow");
+        }
+
+        // not apply to handshake message
+        int macLen = 0;
+        if (writeAuthenticator instanceof MAC) {
+            macLen = ((MAC)writeAuthenticator).MAClen();
+        }
+
+        int fragLen;
+        if (packetSize > 0) {
+            fragLen = Math.min(maxRecordSize, packetSize);
+            fragLen = writeCipher.calculateFragmentSize(
+                    fragLen, macLen, headerSize);
+
+            fragLen = Math.min(fragLen, Record.maxDataSize);
+        } else {
+            fragLen = Record.maxDataSize;
+        }
+
+        if (fragmentSize > 0) {
+            fragLen = Math.min(fragLen, fragmentSize);
+        }
+
+        int dstPos = destination.position();
+        int dstLim = destination.limit();
+        int dstContent = dstPos + headerSize +
+                                writeCipher.getExplicitNonceSize();
+        destination.position(dstContent);
+
+        int remains = Math.min(fragLen, destination.remaining());
+        fragLen = 0;
+        int srcsLen = offset + length;
+        for (int i = offset; (i < srcsLen) && (remains > 0); i++) {
+            int amount = Math.min(sources[i].remaining(), remains);
+            int srcLimit = sources[i].limit();
+            sources[i].limit(sources[i].position() + amount);
+            destination.put(sources[i]);
+            sources[i].limit(srcLimit);         // restore the limit
+            remains -= amount;
+            fragLen += amount;
+        }
+
+        destination.limit(destination.position());
+        destination.position(dstContent);
+
+        if ((debug != null) && Debug.isOn("record")) {
+            System.out.println(Thread.currentThread().getName() +
+                    ", WRITE: " + protocolVersion + " " +
+                    Record.contentName(Record.ct_application_data) +
+                    ", length = " + destination.remaining());
+        }
+
+        // Encrypt the fragment and wrap up a record.
+        long recordSN = encrypt(writeAuthenticator, writeCipher,
+                Record.ct_application_data, destination,
+                dstPos, dstLim, headerSize,
+                protocolVersion, true);
+
+        if ((debug != null) && Debug.isOn("packet")) {
+            ByteBuffer temporary = destination.duplicate();
+            temporary.limit(temporary.position());
+            temporary.position(dstPos);
+            Debug.printHex(
+                    "[Raw write]: length = " + temporary.remaining(),
+                    temporary);
+        }
+
+        // remain the limit unchanged
+        destination.limit(dstLim);
+
+        return new Ciphertext(RecordType.RECORD_APPLICATION_DATA, recordSN);
+    }
+
+    @Override
+    Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
+        if (alertMemos != null && !alertMemos.isEmpty()) {
+            RecordMemo memo = alertMemos.pop();
+
+            int macLen = 0;
+            if (memo.encodeAuthenticator instanceof MAC) {
+                macLen = ((MAC)memo.encodeAuthenticator).MAClen();
+            }
+
+            int dstPos = destination.position();
+            int dstLim = destination.limit();
+            int dstContent = dstPos + headerSize +
+                                writeCipher.getExplicitNonceSize();
+            destination.position(dstContent);
+
+            destination.put(memo.fragment);
+
+            destination.limit(destination.position());
+            destination.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(Record.ct_alert) +
+                        ", length = " + destination.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
+                    Record.ct_alert, destination, dstPos, dstLim, headerSize,
+                    ProtocolVersion.valueOf(memo.majorVersion,
+                            memo.minorVersion), true);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = destination.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            // remain the limit unchanged
+            destination.limit(dstLim);
+
+            return new Ciphertext(RecordType.RECORD_ALERT, recordSN);
+        }
+
+        if (fragmenter != null) {
+            return fragmenter.acquireCiphertext(destination);
+        }
+
+        return null;
+    }
+
+    @Override
+    boolean isEmpty() {
+        return ((fragmenter == null) || fragmenter.isEmpty()) &&
+               ((alertMemos == null) || alertMemos.isEmpty());
+    }
+
+    @Override
+    void initHandshaker() {
+        // clean up
+        fragmenter = null;
+    }
+
+    // buffered record fragment
+    private static class RecordMemo {
+        byte            contentType;
+        byte            majorVersion;
+        byte            minorVersion;
+        int             encodeEpoch;
+        CipherBox       encodeCipher;
+        Authenticator   encodeAuthenticator;
+
+        byte[]          fragment;
+    }
+
+    private static class HandshakeMemo extends RecordMemo {
+        byte            handshakeType;
+        int             messageSequence;
+        int             acquireOffset;
+    }
+
+    private final class DTLSFragmenter {
+        private LinkedList<RecordMemo> handshakeMemos = new LinkedList<>();
+        private int acquireIndex = 0;
+        private int messageSequence = 0;
+        private boolean flightIsReady = false;
+
+        // Per section 4.1.1, RFC 6347:
+        //
+        // If repeated retransmissions do not result in a response, and the
+        // PMTU is unknown, subsequent retransmissions SHOULD back off to a
+        // smaller record size, fragmenting the handshake message as
+        // appropriate.
+        //
+        // In this implementation, two times of retransmits would be attempted
+        // before backing off.  The back off is supported only if the packet
+        // size is bigger than 256 bytes.
+        private int retransmits = 2;            // attemps of retransmits
+
+        void queueUpChangeCipherSpec() {
+
+            // Cleanup if a new flight starts.
+            if (flightIsReady) {
+                handshakeMemos.clear();
+                acquireIndex = 0;
+                flightIsReady = false;
+            }
+
+            RecordMemo memo = new RecordMemo();
+
+            memo.contentType = Record.ct_change_cipher_spec;
+            memo.majorVersion = protocolVersion.major;
+            memo.minorVersion = protocolVersion.minor;
+            memo.encodeEpoch = writeEpoch;
+            memo.encodeCipher = writeCipher;
+            memo.encodeAuthenticator = writeAuthenticator;
+
+            memo.fragment = new byte[1];
+            memo.fragment[0] = 1;
+
+            handshakeMemos.add(memo);
+        }
+
+        void queueUpHandshake(byte[] buf,
+                int offset, int length) throws IOException {
+
+            // Cleanup if a new flight starts.
+            if (flightIsReady) {
+                handshakeMemos.clear();
+                acquireIndex = 0;
+                flightIsReady = false;
+            }
+
+            HandshakeMemo memo = new HandshakeMemo();
+
+            memo.contentType = Record.ct_handshake;
+            memo.majorVersion = protocolVersion.major;
+            memo.minorVersion = protocolVersion.minor;
+            memo.encodeEpoch = writeEpoch;
+            memo.encodeCipher = writeCipher;
+            memo.encodeAuthenticator = writeAuthenticator;
+
+            memo.handshakeType = buf[offset];
+            memo.messageSequence = messageSequence++;
+            memo.acquireOffset = 0;
+            memo.fragment = new byte[length - 4];       // 4: header size
+                                                        //    1: HandshakeType
+                                                        //    3: message length
+            System.arraycopy(buf, offset + 4, memo.fragment, 0, length - 4);
+
+            handshakeHashing(memo, memo.fragment);
+            handshakeMemos.add(memo);
+
+            if ((memo.handshakeType == HandshakeMessage.ht_client_hello) ||
+                (memo.handshakeType == HandshakeMessage.ht_hello_request) ||
+                (memo.handshakeType ==
+                        HandshakeMessage.ht_hello_verify_request) ||
+                (memo.handshakeType == HandshakeMessage.ht_server_hello_done) ||
+                (memo.handshakeType == HandshakeMessage.ht_finished)) {
+
+                flightIsReady = true;
+            }
+        }
+
+        Ciphertext acquireCiphertext(ByteBuffer dstBuf) throws IOException {
+            if (isEmpty()) {
+                if (isRetransmittable()) {
+                    setRetransmission();    // configure for retransmission
+                } else {
+                    return null;
+                }
+            }
+
+            RecordMemo memo = handshakeMemos.get(acquireIndex);
+            HandshakeMemo hsMemo = null;
+            if (memo.contentType == Record.ct_handshake) {
+                hsMemo = (HandshakeMemo)memo;
+            }
+
+            int macLen = 0;
+            if (memo.encodeAuthenticator instanceof MAC) {
+                macLen = ((MAC)memo.encodeAuthenticator).MAClen();
+            }
+
+            // ChangeCipherSpec message is pretty small.  Don't worry about
+            // the fragmentation of ChangeCipherSpec record.
+            int fragLen;
+            if (packetSize > 0) {
+                fragLen = Math.min(maxRecordSize, packetSize);
+                fragLen = memo.encodeCipher.calculateFragmentSize(
+                        fragLen, macLen, 25);   // 25: header size
+                                                //   13: DTLS record
+                                                //   12: DTLS handshake message
+                fragLen = Math.min(fragLen, Record.maxDataSize);
+            } else {
+                fragLen = Record.maxDataSize;
+            }
+
+            if (fragmentSize > 0) {
+                fragLen = Math.min(fragLen, fragmentSize);
+            }
+
+            int dstPos = dstBuf.position();
+            int dstLim = dstBuf.limit();
+            int dstContent = dstPos + headerSize +
+                                    memo.encodeCipher.getExplicitNonceSize();
+            dstBuf.position(dstContent);
+
+            if (hsMemo != null) {
+                fragLen = Math.min(fragLen,
+                        (hsMemo.fragment.length - hsMemo.acquireOffset));
+
+                dstBuf.put(hsMemo.handshakeType);
+                dstBuf.put((byte)((hsMemo.fragment.length >> 16) & 0xFF));
+                dstBuf.put((byte)((hsMemo.fragment.length >> 8) & 0xFF));
+                dstBuf.put((byte)(hsMemo.fragment.length & 0xFF));
+                dstBuf.put((byte)((hsMemo.messageSequence >> 8) & 0xFF));
+                dstBuf.put((byte)(hsMemo.messageSequence & 0xFF));
+                dstBuf.put((byte)((hsMemo.acquireOffset >> 16) & 0xFF));
+                dstBuf.put((byte)((hsMemo.acquireOffset >> 8) & 0xFF));
+                dstBuf.put((byte)(hsMemo.acquireOffset & 0xFF));
+                dstBuf.put((byte)((fragLen >> 16) & 0xFF));
+                dstBuf.put((byte)((fragLen >> 8) & 0xFF));
+                dstBuf.put((byte)(fragLen & 0xFF));
+                dstBuf.put(hsMemo.fragment, hsMemo.acquireOffset, fragLen);
+            } else {
+                fragLen = Math.min(fragLen, memo.fragment.length);
+                dstBuf.put(memo.fragment, 0, fragLen);
+            }
+
+            dstBuf.limit(dstBuf.position());
+            dstBuf.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(memo.contentType) +
+                        ", length = " + dstBuf.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
+                    memo.contentType, dstBuf,
+                    dstPos, dstLim, headerSize,
+                    ProtocolVersion.valueOf(memo.majorVersion,
+                            memo.minorVersion), true);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = dstBuf.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            // remain the limit unchanged
+            dstBuf.limit(dstLim);
+
+            // Reset the fragmentation offset.
+            if (hsMemo != null) {
+                hsMemo.acquireOffset += fragLen;
+                if (hsMemo.acquireOffset == hsMemo.fragment.length) {
+                    acquireIndex++;
+                }
+
+                return new Ciphertext(RecordType.valueOf(
+                        hsMemo.contentType, hsMemo.handshakeType), recordSN);
+            } else {
+                acquireIndex++;
+                return new Ciphertext(
+                        RecordType.RECORD_CHANGE_CIPHER_SPEC, recordSN);
+            }
+        }
+
+        private void handshakeHashing(HandshakeMemo hsFrag, byte[] hsBody) {
+
+            byte hsType = hsFrag.handshakeType;
+            if ((hsType == HandshakeMessage.ht_hello_request) ||
+                (hsType == HandshakeMessage.ht_hello_verify_request)) {
+
+                // omitted from handshake hash computation
+                return;
+            }
+
+            if ((hsFrag.messageSequence == 0) &&
+                (hsType == HandshakeMessage.ht_client_hello)) {
+
+                // omit initial ClientHello message
+                //
+                //  2: ClientHello.client_version
+                // 32: ClientHello.random
+                int sidLen = hsBody[34];
+
+                if (sidLen == 0) {      // empty session_id, initial handshake
+                    return;
+                }
+            }
+
+            // calculate the DTLS header
+            byte[] temporary = new byte[12];    // 12: handshake header size
+
+            // Handshake.msg_type
+            temporary[0] = hsFrag.handshakeType;
+
+            // Handshake.length
+            temporary[1] = (byte)((hsBody.length >> 16) & 0xFF);
+            temporary[2] = (byte)((hsBody.length >> 8) & 0xFF);
+            temporary[3] = (byte)(hsBody.length & 0xFF);
+
+            // Handshake.message_seq
+            temporary[4] = (byte)((hsFrag.messageSequence >> 8) & 0xFF);
+            temporary[5] = (byte)(hsFrag.messageSequence & 0xFF);
+
+            // Handshake.fragment_offset
+            temporary[6] = 0;
+            temporary[7] = 0;
+            temporary[8] = 0;
+
+            // Handshake.fragment_length
+            temporary[9] = temporary[1];
+            temporary[10] = temporary[2];
+            temporary[11] = temporary[3];
+
+            if ((hsType != HandshakeMessage.ht_finished) &&
+                (hsType != HandshakeMessage.ht_certificate_verify)) {
+
+                handshakeHash.update(temporary, 0, 12);
+                handshakeHash.update(hsBody, 0, hsBody.length);
+            } else {
+                // Reserve until this handshake message has been processed.
+                handshakeHash.reserve(temporary, 0, 12);
+                handshakeHash.reserve(hsBody, 0, hsBody.length);
+            }
+
+        }
+
+        boolean isEmpty() {
+            if (!flightIsReady || handshakeMemos.isEmpty() ||
+                    acquireIndex >= handshakeMemos.size()) {
+                return true;
+            }
+
+            return false;
+        }
+
+        boolean isRetransmittable() {
+            return (flightIsReady && !handshakeMemos.isEmpty() &&
+                                (acquireIndex >= handshakeMemos.size()));
+        }
+
+        private void setRetransmission() {
+            acquireIndex = 0;
+            for (RecordMemo memo : handshakeMemos) {
+                if (memo instanceof HandshakeMemo) {
+                    HandshakeMemo hmemo = (HandshakeMemo)memo;
+                    hmemo.acquireOffset = 0;
+                }
+            }
+
+            // Shrink packet size if:
+            // 1. maximum fragment size is allowed, in which case the packet
+            //    size is configured bigger than maxRecordSize;
+            // 2. maximum packet is bigger than 256 bytes;
+            // 3. two times of retransmits have been attempted.
+            if ((packetSize <= maxRecordSize) &&
+                    (packetSize > 256) && ((retransmits--) <= 0)) {
+
+                // shrink packet size
+                shrinkPacketSize();
+                retransmits = 2;        // attemps of retransmits
+            }
+        }
+
+        private void shrinkPacketSize() {
+            packetSize = Math.max(256, packetSize / 2);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+/**
+ * DTLS record
+ */
+interface DTLSRecord extends Record {
+
+    static final int    headerSize = 13;            // DTLS record header
+
+    static final int    handshakeHeaderSize = 12;   // DTLS handshake header
+
+    /*
+     * The size of the header plus the max IV length
+     */
+    static final int    headerPlusMaxIVSize =
+                                      headerSize        // header
+                                    + maxIVLength;      // iv
+
+    /*
+     * The maximum size that may be increased when translating plaintext to
+     * ciphertext fragment.
+     */
+    static final int    maxPlaintextPlusSize =
+                                      headerSize        // header
+                                    + maxIVLength       // iv
+                                    + maxMacSize        // MAC or AEAD tag
+                                    + maxPadding;       // block cipher padding
+
+    /*
+     * the maximum record size
+     */
+    static final int    maxRecordSize =
+                                      headerPlusMaxIVSize   // header + iv
+                                    + maxDataSize           // data
+                                    + maxPadding            // padding
+                                    + maxMacSize;           // MAC or AEAD tag
+
+    /*
+     * For CBC protection in SSL3/TLS1, we break some plaintext into two
+     * packets.  Max application data size for the second packet.
+     */
+    static final int    maxDataSizeMinusOneByteRecord =
+                                  maxDataSize       // max data size
+                                - (                 // max one byte record size
+                                      headerPlusMaxIVSize   // header + iv
+                                    + 1             // one byte data
+                                    + maxPadding    // padding
+                                    + maxMacSize    // MAC
+                                  );
+
+    /*
+     * Maximum record size for alert and change cipher spec records.
+     * They only contain 2 and 1 bytes of data, respectively.
+     * Allocate a smaller array.
+     */
+    static final int    maxAlertRecordSize =
+                                      headerPlusMaxIVSize   // header + iv
+                                    + 2                     // alert
+                                    + maxPadding            // padding
+                                    + maxMacSize;           // MAC
+
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Tue Jun 02 04:01:04 2015 +0000
@@ -29,6 +29,9 @@
 import java.security.AccessController;
 import java.util.Locale;
 
+import sun.misc.HexDumpEncoder;
+import java.nio.ByteBuffer;
+
 import sun.security.action.GetPropertyAction;
 
 /**
@@ -198,4 +201,47 @@
     static String toString(byte[] b) {
         return sun.security.util.Debug.toString(b);
     }
+
+    static void printHex(String prefix, byte[] bytes) {
+        HexDumpEncoder dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                dump.encodeBuffer(bytes, System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
+
+    static void printHex(String prefix, ByteBuffer bb) {
+        HexDumpEncoder dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                dump.encodeBuffer(bb.slice(), System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
+
+    static void printHex(String prefix, byte[] bytes, int offset, int length) {
+        HexDumpEncoder dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length);
+                dump.encodeBuffer(bb, System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineArgs.java	Mon Jun 01 10:29:06 2015 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.nio.*;
-
-/*
- * A multi-purpose class which handles all of the SSLEngine arguments.
- * It validates arguments, checks for RO conditions, does space
- * calculations, performs scatter/gather, etc.
- *
- * @author Brad R. Wetmore
- */
-class EngineArgs {
-
-    /*
-     * Keep track of the input parameters.
-     */
-    ByteBuffer netData;
-    ByteBuffer [] appData;
-
-    private int offset;         // offset/len for the appData array.
-    private int len;
-
-    /*
-     * The initial pos/limit conditions.  This is useful because we can
-     * quickly calculate the amount consumed/produced in successful
-     * operations, or easily return the buffers to their pre-error
-     * conditions.
-     */
-    private int netPos;
-    private int netLim;
-
-    private int [] appPoss;
-    private int [] appLims;
-
-    /*
-     * Sum total of the space remaining in all of the appData buffers
-     */
-    private int appRemaining = 0;
-
-    private boolean wrapMethod;
-
-    /*
-     * Called by the SSLEngine.wrap() method.
-     */
-    EngineArgs(ByteBuffer [] appData, int offset, int len,
-            ByteBuffer netData) {
-        this.wrapMethod = true;
-        init(netData, appData, offset, len);
-    }
-
-    /*
-     * Called by the SSLEngine.unwrap() method.
-     */
-    EngineArgs(ByteBuffer netData, ByteBuffer [] appData, int offset,
-            int len) {
-        this.wrapMethod = false;
-        init(netData, appData, offset, len);
-    }
-
-    /*
-     * The main initialization method for the arguments.  Most
-     * of them are pretty obvious as to what they do.
-     *
-     * Since we're already iterating over appData array for validity
-     * checking, we also keep track of how much remainging space is
-     * available.  Info is used in both unwrap (to see if there is
-     * enough space available in the destination), and in wrap (to
-     * determine how much more we can copy into the outgoing data
-     * buffer.
-     */
-    private void init(ByteBuffer netData, ByteBuffer [] appData,
-            int offset, int len) {
-
-        if ((netData == null) || (appData == null)) {
-            throw new IllegalArgumentException("src/dst is null");
-        }
-
-        if ((offset < 0) || (len < 0) || (offset > appData.length - len)) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (wrapMethod && netData.isReadOnly()) {
-            throw new ReadOnlyBufferException();
-        }
-
-        netPos = netData.position();
-        netLim = netData.limit();
-
-        appPoss = new int [appData.length];
-        appLims = new int [appData.length];
-
-        for (int i = offset; i < offset + len; i++) {
-            if (appData[i] == null) {
-                throw new IllegalArgumentException(
-                    "appData[" + i + "] == null");
-            }
-
-            /*
-             * If we're unwrapping, then check to make sure our
-             * destination bufffers are writable.
-             */
-            if (!wrapMethod && appData[i].isReadOnly()) {
-                throw new ReadOnlyBufferException();
-            }
-
-            appRemaining += appData[i].remaining();
-
-            appPoss[i] = appData[i].position();
-            appLims[i] = appData[i].limit();
-        }
-
-        /*
-         * Ok, looks like we have a good set of args, let's
-         * store the rest of this stuff.
-         */
-        this.netData = netData;
-        this.appData = appData;
-        this.offset = offset;
-        this.len = len;
-    }
-
-    /*
-     * Given spaceLeft bytes to transfer, gather up that much data
-     * from the appData buffers (starting at offset in the array),
-     * and transfer it into the netData buffer.
-     *
-     * The user has already ensured there is enough room.
-     */
-    void gather(int spaceLeft) {
-        for (int i = offset; (i < (offset + len)) && (spaceLeft > 0); i++) {
-            int amount = Math.min(appData[i].remaining(), spaceLeft);
-            appData[i].limit(appData[i].position() + amount);
-            netData.put(appData[i]);
-            appRemaining -= amount;
-            spaceLeft -= amount;
-        }
-    }
-
-    /*
-     * Using the supplied buffer, scatter the data into the appData buffers
-     * (starting at offset in the array).
-     *
-     * The user has already ensured there is enough room.
-     */
-    void scatter(ByteBuffer readyData) {
-        int amountLeft = readyData.remaining();
-
-        for (int i = offset; (i < (offset + len)) && (amountLeft > 0);
-                i++) {
-            int amount = Math.min(appData[i].remaining(), amountLeft);
-            readyData.limit(readyData.position() + amount);
-            appData[i].put(readyData);
-            amountLeft -= amount;
-        }
-        assert(readyData.remaining() == 0);
-    }
-
-    int getAppRemaining() {
-        return appRemaining;
-    }
-
-    /*
-     * Calculate the bytesConsumed/byteProduced.  Aren't you glad
-     * we saved this off earlier?
-     */
-    int deltaNet() {
-        return (netData.position() - netPos);
-    }
-
-    /*
-     * Calculate the bytesConsumed/byteProduced.  Aren't you glad
-     * we saved this off earlier?
-     */
-    int deltaApp() {
-        int sum = 0;    // Only calculating 2^14 here, don't need a long.
-
-        for (int i = offset; i < offset + len; i++) {
-            sum += appData[i].position() - appPoss[i];
-        }
-
-        return sum;
-    }
-
-    /*
-     * In the case of Exception, we want to reset the positions
-     * to appear as though no data has been consumed or produced.
-     *
-     * Currently, this method is only called as we are preparing to
-     * fail out, and thus we don't need to actually recalculate
-     * appRemaining.  If that assumption changes, that variable should
-     * be updated here.
-     */
-    void resetPos() {
-        netData.position(netPos);
-        for (int i = offset; i < offset + len; i++) {
-            // See comment above about recalculating appRemaining.
-            appData[i].position(appPoss[i]);
-        }
-    }
-
-    /*
-     * We are doing lots of ByteBuffer manipulations, in which case
-     * we need to make sure that the limits get set back correctly.
-     * This is one of the last things to get done before returning to
-     * the user.
-     */
-    void resetLim() {
-        netData.limit(netLim);
-        for (int i = offset; i < offset + len; i++) {
-            appData[i].limit(appLims[i]);
-        }
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineInputRecord.java	Mon Jun 01 10:29:06 2015 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,427 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-import javax.net.ssl.*;
-import javax.crypto.BadPaddingException;
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * Wrapper class around InputRecord.
- *
- * Application data is kept external to the InputRecord,
- * but handshake data (alert/change_cipher_spec/handshake) will
- * be kept internally in the ByteArrayInputStream.
- *
- * @author Brad Wetmore
- */
-final class EngineInputRecord extends InputRecord {
-
-    private SSLEngineImpl engine;
-
-    /*
-     * A dummy ByteBuffer we'll pass back even when the data
-     * is stored internally.  It'll never actually be used.
-     */
-    static private ByteBuffer tmpBB = ByteBuffer.allocate(0);
-
-    /*
-     * Flag to tell whether the last read/parsed data resides
-     * internal in the ByteArrayInputStream, or in the external
-     * buffers.
-     */
-    private boolean internalData;
-
-    EngineInputRecord(SSLEngineImpl engine) {
-        super();
-        this.engine = engine;
-    }
-
-    @Override
-    byte contentType() {
-        if (internalData) {
-            return super.contentType();
-        } else {
-            return ct_application_data;
-        }
-    }
-
-    /*
-     * Check if there is enough inbound data in the ByteBuffer
-     * to make a inbound packet.  Look for both SSLv2 and SSLv3.
-     *
-     * @return -1 if there are not enough bytes to tell (small header),
-     */
-    int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
-
-        /*
-         * SSLv2 length field is in bytes 0/1
-         * SSLv3/TLS length field is in bytes 3/4
-         */
-        if (buf.remaining() < 5) {
-            return -1;
-        }
-
-        int pos = buf.position();
-        byte byteZero = buf.get(pos);
-
-        int len = 0;
-
-        /*
-         * If we have already verified previous packets, we can
-         * ignore the verifications steps, and jump right to the
-         * determination.  Otherwise, try one last hueristic to
-         * see if it's SSL/TLS.
-         */
-        if (formatVerified ||
-                (byteZero == ct_handshake) ||
-                (byteZero == ct_alert)) {
-            /*
-             * Last sanity check that it's not a wild record
-             */
-            ProtocolVersion recordVersion =
-                ProtocolVersion.valueOf(buf.get(pos + 1), buf.get(pos + 2));
-
-            // check the record version
-            checkRecordVersion(recordVersion, false);
-
-            /*
-             * Reasonably sure this is a V3, disable further checks.
-             * We can't do the same in the v2 check below, because
-             * read still needs to parse/handle the v2 clientHello.
-             */
-            formatVerified = true;
-
-            /*
-             * One of the SSLv3/TLS message types.
-             */
-            len = ((buf.get(pos + 3) & 0xff) << 8) +
-                (buf.get(pos + 4) & 0xff) + headerSize;
-
-        } else {
-            /*
-             * Must be SSLv2 or something unknown.
-             * Check if it's short (2 bytes) or
-             * long (3) header.
-             *
-             * Internals can warn about unsupported SSLv2
-             */
-            boolean isShort = ((byteZero & 0x80) != 0);
-
-            if (isShort &&
-                    ((buf.get(pos + 2) == 1) || buf.get(pos + 2) == 4)) {
-
-                ProtocolVersion recordVersion =
-                    ProtocolVersion.valueOf(buf.get(pos + 3), buf.get(pos + 4));
-
-                // check the record version
-                checkRecordVersion(recordVersion, true);
-
-                /*
-                 * Client or Server Hello
-                 */
-                int mask = (isShort ? 0x7f : 0x3f);
-                len = ((byteZero & mask) << 8) + (buf.get(pos + 1) & 0xff) +
-                    (isShort ? 2 : 3);
-
-            } else {
-                // Gobblygook!
-                throw new SSLException(
-                    "Unrecognized SSL message, plaintext connection?");
-            }
-        }
-
-        return len;
-    }
-
-    /*
-     * Pass the data down if it's internally cached, otherwise
-     * do it here.
-     *
-     * If internal data, data is decrypted internally.
-     *
-     * If external data(app), return a new ByteBuffer with data to
-     * process.
-     */
-    ByteBuffer decrypt(Authenticator authenticator,
-            CipherBox box, ByteBuffer bb) throws BadPaddingException {
-
-        if (internalData) {
-            decrypt(authenticator, box);   // MAC is checked during decryption
-            return tmpBB;
-        }
-
-        BadPaddingException reservedBPE = null;
-        int tagLen =
-            (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
-        int cipheredLength = bb.remaining();
-
-        if (!box.isNullCipher()) {
-            try {
-                // apply explicit nonce for AEAD/CBC cipher suites if needed
-                int nonceSize =
-                    box.applyExplicitNonce(authenticator, contentType(), bb);
-
-                // decrypt the content
-                if (box.isAEADMode()) {
-                    // DON'T encrypt the nonce_explicit for AEAD mode
-                    bb.position(bb.position() + nonceSize);
-                }   // The explicit IV for CBC mode can be decrypted.
-
-                // Note that the CipherBox.decrypt() does not change
-                // the capacity of the buffer.
-                box.decrypt(bb, tagLen);
-                bb.position(nonceSize); // We don't actually remove the nonce.
-            } catch (BadPaddingException bpe) {
-                // RFC 2246 states that decryption_failed should be used
-                // for this purpose. However, that allows certain attacks,
-                // so we just send bad record MAC. We also need to make
-                // sure to always check the MAC to avoid a timing attack
-                // for the same issue. See paper by Vaudenay et al and the
-                // update in RFC 4346/5246.
-                //
-                // Failover to message authentication code checking.
-                reservedBPE = bpe;
-            }
-        }
-
-        // Requires message authentication code for null, stream and block
-        // cipher suites.
-        if ((authenticator instanceof MAC) && (tagLen != 0)) {
-            MAC signer = (MAC)authenticator;
-            int macOffset = bb.limit() - tagLen;
-
-            // Note that although it is not necessary, we run the same MAC
-            // computation and comparison on the payload for both stream
-            // cipher and CBC block cipher.
-            if (bb.remaining() < tagLen) {
-                // negative data length, something is wrong
-                if (reservedBPE == null) {
-                    reservedBPE = new BadPaddingException("bad record");
-                }
-
-                // set offset of the dummy MAC
-                macOffset = cipheredLength - tagLen;
-                bb.limit(cipheredLength);
-            }
-
-            // Run MAC computation and comparison on the payload.
-            if (checkMacTags(contentType(), bb, signer, false)) {
-                if (reservedBPE == null) {
-                    reservedBPE = new BadPaddingException("bad record MAC");
-                }
-            }
-
-            // Run MAC computation and comparison on the remainder.
-            //
-            // It is only necessary for CBC block cipher.  It is used to get a
-            // constant time of MAC computation and comparison on each record.
-            if (box.isCBCMode()) {
-                int remainingLen = calculateRemainingLen(
-                                        signer, cipheredLength, macOffset);
-
-                // NOTE: here we use the InputRecord.buf because I did not find
-                // an effective way to work on ByteBuffer when its capacity is
-                // less than remainingLen.
-
-                // NOTE: remainingLen may be bigger (less than 1 block of the
-                // hash algorithm of the MAC) than the cipheredLength. However,
-                // We won't need to worry about it because we always use a
-                // maximum buffer for every record.  We need a change here if
-                // we use small buffer size in the future.
-                if (remainingLen > buf.length) {
-                    // unlikely to happen, just a placehold
-                    throw new RuntimeException(
-                        "Internal buffer capacity error");
-                }
-
-                // Won't need to worry about the result on the remainder. And
-                // then we won't need to worry about what's actual data to
-                // check MAC tag on.  We start the check from the header of the
-                // buffer so that we don't need to construct a new byte buffer.
-                checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
-            }
-
-            bb.limit(macOffset);
-        }
-
-        // Is it a failover?
-        if (reservedBPE != null) {
-            throw reservedBPE;
-        }
-
-        return bb.slice();
-    }
-
-    /*
-     * Run MAC computation and comparison
-     *
-     * Please DON'T change the content of the ByteBuffer parameter!
-     */
-    private static boolean checkMacTags(byte contentType, ByteBuffer bb,
-            MAC signer, boolean isSimulated) {
-
-        int position = bb.position();
-        int tagLen = signer.MAClen();
-        int lim = bb.limit();
-        int macData = lim - tagLen;
-
-        bb.limit(macData);
-        byte[] hash = signer.compute(contentType, bb, isSimulated);
-        if (hash == null || tagLen != hash.length) {
-            // Something is wrong with MAC implementation.
-            throw new RuntimeException("Internal MAC error");
-        }
-
-        bb.position(macData);
-        bb.limit(lim);
-        try {
-            int[] results = compareMacTags(bb, hash);
-            return (results[0] != 0);
-        } finally {
-            // reset to the data
-            bb.position(position);
-            bb.limit(macData);
-        }
-    }
-
-    /*
-     * A constant-time comparison of the MAC tags.
-     *
-     * Please DON'T change the content of the ByteBuffer parameter!
-     */
-    private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
-
-        // An array of hits is used to prevent Hotspot optimization for
-        // the purpose of a constant-time check.
-        int[] results = {0, 0};     // {missed #, matched #}
-
-        // The caller ensures there are enough bytes available in the buffer.
-        // So we won't need to check the remaining of the buffer.
-        for (int i = 0; i < tag.length; i++) {
-            if (bb.get() != tag[i]) {
-                results[0]++;       // mismatched bytes
-            } else {
-                results[1]++;       // matched bytes
-            }
-        }
-
-        return results;
-    }
-
-    /*
-     * Override the actual write below.  We do things this way to be
-     * consistent with InputRecord.  InputRecord may try to write out
-     * data to the peer, and *then* throw an Exception.  This forces
-     * data to be generated/output before the exception is ever
-     * generated.
-     */
-    @Override
-    void writeBuffer(OutputStream s, byte [] buf, int off, int len)
-            throws IOException {
-        /*
-         * Copy data out of buffer, it's ready to go.
-         */
-        ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, 0, len).flip();
-        engine.writer.putOutboundDataSync(netBB);
-    }
-
-    /*
-     * Delineate or read a complete packet from src.
-     *
-     * If internal data (hs, alert, ccs), the data is read and
-     * stored internally.
-     *
-     * If external data (app), return a new ByteBuffer which points
-     * to the data to process.
-     */
-    ByteBuffer read(ByteBuffer srcBB) throws IOException {
-        /*
-         * Could have a src == null/dst == null check here,
-         * but that was already checked by SSLEngine.unwrap before
-         * ever attempting to read.
-         */
-
-        /*
-         * If we have anything besides application data,
-         * or if we haven't even done the initial v2 verification,
-         * we send this down to be processed by the underlying
-         * internal cache.
-         */
-        if (!formatVerified ||
-                (srcBB.get(srcBB.position()) != ct_application_data)) {
-            internalData = true;
-            read(new ByteBufferInputStream(srcBB), (OutputStream) null);
-            return tmpBB;
-        }
-
-        internalData = false;
-
-        int srcPos = srcBB.position();
-        int srcLim = srcBB.limit();
-
-        ProtocolVersion recordVersion = ProtocolVersion.valueOf(
-                srcBB.get(srcPos + 1), srcBB.get(srcPos + 2));
-
-        // check the record version
-        checkRecordVersion(recordVersion, false);
-
-        /*
-         * It's really application data.  How much to consume?
-         * Jump over the header.
-         */
-        int len = bytesInCompletePacket(srcBB);
-        assert(len > 0);
-
-        if (debug != null && Debug.isOn("packet")) {
-            try {
-                HexDumpEncoder hd = new HexDumpEncoder();
-                ByteBuffer bb = srcBB.duplicate();  // Use copy of BB
-                bb.limit(srcPos + len);
-
-                System.out.println("[Raw read (bb)]: length = " + len);
-                hd.encodeBuffer(bb, System.out);
-            } catch (IOException e) { }
-        }
-
-        // Demarcate past header to end of packet.
-        srcBB.position(srcPos + headerSize);
-        srcBB.limit(srcPos + len);
-
-        // Protect remainder of buffer, create slice to actually
-        // operate on.
-        ByteBuffer bb = srcBB.slice();
-
-        srcBB.position(srcBB.limit());
-        srcBB.limit(srcLim);
-
-        return bb;
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineOutputRecord.java	Mon Jun 01 10:29:06 2015 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,329 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-package sun.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-
-/**
- * A OutputRecord class extension which uses external ByteBuffers
- * or the internal ByteArrayOutputStream for data manipulations.
- * <P>
- * Instead of rewriting this entire class
- * to use ByteBuffers, we leave things intact, so handshake, CCS,
- * and alerts will continue to use the internal buffers, but application
- * data will use external buffers.
- *
- * @author Brad Wetmore
- */
-final class EngineOutputRecord extends OutputRecord {
-
-    private SSLEngineImpl engine;
-    private EngineWriter writer;
-
-    private boolean finishedMsg = false;
-
-    /*
-     * All handshake hashing is done by the superclass
-     */
-
-    /*
-     * Default constructor makes a record supporting the maximum
-     * SSL record size.  It allocates the header bytes directly.
-     *
-     * @param type the content type for the record
-     */
-    EngineOutputRecord(byte type, SSLEngineImpl engine) {
-        super(type, recordSize(type));
-        this.engine = engine;
-        writer = engine.writer;
-    }
-
-    /**
-     * Get the size of the buffer we need for records of the specified
-     * type.
-     * <P>
-     * Application data buffers will provide their own byte buffers,
-     * and will not use the internal byte caching.
-     */
-    private static int recordSize(byte type) {
-        switch (type) {
-
-        case ct_change_cipher_spec:
-        case ct_alert:
-            return maxAlertRecordSize;
-
-        case ct_handshake:
-            return maxRecordSize;
-
-        case ct_application_data:
-            return 0;
-        }
-
-        throw new RuntimeException("Unknown record type: " + type);
-    }
-
-    void setFinishedMsg() {
-        finishedMsg = true;
-    }
-
-    @Override
-    public void flush() throws IOException {
-        finishedMsg = false;
-    }
-
-    boolean isFinishedMsg() {
-        return finishedMsg;
-    }
-
-    /*
-     * Override the actual write below.  We do things this way to be
-     * consistent with InputRecord.  InputRecord may try to write out
-     * data to the peer, and *then* throw an Exception.  This forces
-     * data to be generated/output before the exception is ever
-     * generated.
-     */
-    @Override
-    void writeBuffer(OutputStream s, byte [] buf, int off, int len,
-            int debugOffset) throws IOException {
-        /*
-         * Copy data out of buffer, it's ready to go.
-         */
-        ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, off, len).flip();
-        writer.putOutboundData(netBB);
-    }
-
-    /*
-     * Main method for writing non-application data.
-     * We MAC/encrypt, then send down for processing.
-     */
-    void write(Authenticator authenticator, CipherBox writeCipher)
-            throws IOException {
-
-        /*
-         * Sanity check.
-         */
-        switch (contentType()) {
-            case ct_change_cipher_spec:
-            case ct_alert:
-            case ct_handshake:
-                break;
-            default:
-                throw new RuntimeException("unexpected byte buffers");
-        }
-
-        /*
-         * Don't bother to really write empty records.  We went this
-         * far to drive the handshake machinery, for correctness; not
-         * writing empty records improves performance by cutting CPU
-         * time and network resource usage.  Also, some protocol
-         * implementations are fragile and don't like to see empty
-         * records, so this increases robustness.
-         *
-         * (Even change cipher spec messages have a byte of data!)
-         */
-        if (!isEmpty()) {
-            // compress();              // eventually
-            encrypt(authenticator, writeCipher);
-
-            // send down for processing
-            write((OutputStream)null, false, (ByteArrayOutputStream)null);
-        }
-        return;
-    }
-
-    /**
-     * Main wrap/write driver.
-     */
-    void write(EngineArgs ea, Authenticator authenticator,
-            CipherBox writeCipher) throws IOException {
-        /*
-         * sanity check to make sure someone didn't inadvertantly
-         * send us an impossible combination we don't know how
-         * to process.
-         */
-        assert(contentType() == ct_application_data);
-
-        /*
-         * Have we set the MAC's yet?  If not, we're not ready
-         * to process application data yet.
-         */
-        if (authenticator == MAC.NULL) {
-            return;
-        }
-
-        /*
-         * Don't bother to really write empty records.  We went this
-         * far to drive the handshake machinery, for correctness; not
-         * writing empty records improves performance by cutting CPU
-         * time and network resource usage.  Also, some protocol
-         * implementations are fragile and don't like to see empty
-         * records, so this increases robustness.
-         */
-        if (ea.getAppRemaining() == 0) {
-            return;
-        }
-
-        /*
-         * By default, we counter chosen plaintext issues on CBC mode
-         * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
-         * data in the first record of every payload, and the rest in
-         * subsequent record(s). Note that the issues have been solved in
-         * TLS 1.1 or later.
-         *
-         * It is not necessary to split the very first application record of
-         * a freshly negotiated TLS session, as there is no previous
-         * application data to guess.  To improve compatibility, we will not
-         * split such records.
-         *
-         * Because of the compatibility, we'd better produce no more than
-         * SSLSession.getPacketBufferSize() net data for each wrap. As we
-         * need a one-byte record at first, the 2nd record size should be
-         * equal to or less than Record.maxDataSizeMinusOneByteRecord.
-         *
-         * This avoids issues in the outbound direction.  For a full fix,
-         * the peer must have similar protections.
-         */
-        int length;
-        if (engine.needToSplitPayload(writeCipher, protocolVersion)) {
-            write(ea, authenticator, writeCipher, 0x01);
-            ea.resetLim();      // reset application data buffer limit
-            length = Math.min(ea.getAppRemaining(),
-                        maxDataSizeMinusOneByteRecord);
-        } else {
-            length = Math.min(ea.getAppRemaining(), maxDataSize);
-        }
-
-        // Don't bother to really write empty records.
-        if (length > 0) {
-            write(ea, authenticator, writeCipher, length);
-        }
-
-        return;
-    }
-
-    void write(EngineArgs ea, Authenticator authenticator,
-            CipherBox writeCipher, int length) throws IOException {
-        /*
-         * Copy out existing buffer values.
-         */
-        ByteBuffer dstBB = ea.netData;
-        int dstPos = dstBB.position();
-        int dstLim = dstBB.limit();
-
-        /*
-         * Where to put the data.  Jump over the header.
-         *
-         * Don't need to worry about SSLv2 rewrites, if we're here,
-         * that's long since done.
-         */
-        int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize();
-        dstBB.position(dstData);
-
-        /*
-         * transfer application data into the network data buffer
-         */
-        ea.gather(length);
-        dstBB.limit(dstBB.position());
-        dstBB.position(dstData);
-
-        /*
-         * "flip" but skip over header again, add MAC & encrypt
-         */
-        if (authenticator instanceof MAC) {
-            MAC signer = (MAC)authenticator;
-            if (signer.MAClen() != 0) {
-                byte[] hash = signer.compute(contentType(), dstBB, false);
-
-                /*
-                 * position was advanced to limit in compute above.
-                 *
-                 * Mark next area as writable (above layers should have
-                 * established that we have plenty of room), then write
-                 * out the hash.
-                 */
-                dstBB.limit(dstBB.limit() + hash.length);
-                dstBB.put(hash);
-
-                // reset the position and limit
-                dstBB.limit(dstBB.position());
-                dstBB.position(dstData);
-            }
-        }
-
-        if (!writeCipher.isNullCipher()) {
-            /*
-             * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1
-             * or later.
-             */
-            if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
-                    (writeCipher.isCBCMode() || writeCipher.isAEADMode())) {
-                byte[] nonce = writeCipher.createExplicitNonce(
-                        authenticator, contentType(), dstBB.remaining());
-                dstBB.position(dstPos + headerSize);
-                dstBB.put(nonce);
-                if (!writeCipher.isAEADMode()) {
-                    // The explicit IV in TLS 1.1 and later can be encrypted.
-                    dstBB.position(dstPos + headerSize);
-                }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
-            }
-
-            /*
-             * Encrypt may pad, so again the limit may have changed.
-             */
-            writeCipher.encrypt(dstBB, dstLim);
-
-            if ((debug != null) && (Debug.isOn("record") ||
-                    (Debug.isOn("handshake") &&
-                        (contentType() == ct_change_cipher_spec)))) {
-                System.out.println(Thread.currentThread().getName()
-                    // v3.0/v3.1 ...
-                    + ", WRITE: " + protocolVersion
-                    + " " + InputRecord.contentName(contentType())
-                    + ", length = " + length);
-            }
-        } else {
-            dstBB.position(dstBB.limit());
-        }
-
-        int packetLength = dstBB.limit() - dstPos - headerSize;
-
-        /*
-         * Finish out the record header.
-         */
-        dstBB.put(dstPos, contentType());
-        dstBB.put(dstPos + 1, protocolVersion.major);
-        dstBB.put(dstPos + 2, protocolVersion.minor);
-        dstBB.put(dstPos + 3, (byte)(packetLength >> 8));
-        dstBB.put(dstPos + 4, (byte)packetLength);
-
-        /*
-         * Position was already set by encrypt() above.
-         */
-        dstBB.limit(dstLim);
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineWriter.java	Mon Jun 01 10:29:06 2015 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,244 +0,0 @@
-/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.ssl;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import javax.net.ssl.SSLEngineResult.HandshakeStatus;
-import sun.misc.HexDumpEncoder;
-
-/**
- * A class to help abstract away SSLEngine writing synchronization.
- */
-final class EngineWriter {
-
-    /*
-     * Outgoing handshake Data waiting for a ride is stored here.
-     * Normal application data is written directly into the outbound
-     * buffer, but handshake data can be written out at any time,
-     * so we have buffer it somewhere.
-     *
-     * When wrap is called, we first check to see if there is
-     * any data waiting, then if we're in a data transfer state,
-     * we try to write app data.
-     *
-     * This will contain either ByteBuffers, or the marker
-     * HandshakeStatus.FINISHED to signify that a handshake just completed.
-     */
-    private LinkedList<Object> outboundList;
-
-    private boolean outboundClosed = false;
-
-    /* Class and subclass dynamic debugging support */
-    private static final Debug debug = Debug.getInstance("ssl");
-
-    EngineWriter() {
-        outboundList = new LinkedList<Object>();
-    }
-
-    /*
-     * Upper levels assured us we had room for at least one packet of data.
-     * As per the SSLEngine spec, we only return one SSL packets worth of
-     * data.
-     */
-    private HandshakeStatus getOutboundData(ByteBuffer dstBB) {
-
-        Object msg = outboundList.removeFirst();
-        assert(msg instanceof ByteBuffer);
-
-        ByteBuffer bbIn = (ByteBuffer) msg;
-        assert(dstBB.remaining() >= bbIn.remaining());
-
-        dstBB.put(bbIn);
-
-        /*
-         * If we have more data in the queue, it's either
-         * a finished message, or an indication that we need
-         * to call wrap again.
-         */
-        if (hasOutboundDataInternal()) {
-            msg = outboundList.getFirst();
-            if (msg == HandshakeStatus.FINISHED) {
-                outboundList.removeFirst();     // consume the message
-                return HandshakeStatus.FINISHED;
-            } else {
-                return HandshakeStatus.NEED_WRAP;
-            }
-        } else {
-            return null;
-        }
-    }
-
-    /*
-     * Properly orders the output of the data written to the wrap call.
-     * This is only handshake data, application data goes through the
-     * other writeRecord.
-     */
-    synchronized void writeRecord(EngineOutputRecord outputRecord,
-            Authenticator authenticator,
-            CipherBox writeCipher) throws IOException {
-
-        /*
-         * Only output if we're still open.
-         */
-        if (outboundClosed) {
-            throw new IOException("writer side was already closed.");
-        }
-
-        outputRecord.write(authenticator, writeCipher);
-
-        /*
-         * Did our handshakers notify that we just sent the
-         * Finished message?
-         *
-         * Add an "I'm finished" message to the queue.
-         */
-        if (outputRecord.isFinishedMsg()) {
-            outboundList.addLast(HandshakeStatus.FINISHED);
-        }
-    }
-
-    /*
-     * Output the packet info.
-     */
-    private void dumpPacket(EngineArgs ea, boolean hsData) {
-        try {
-            HexDumpEncoder hd = new HexDumpEncoder();
-
-            ByteBuffer bb = ea.netData.duplicate();
-
-            int pos = bb.position();
-            bb.position(pos - ea.deltaNet());
-            bb.limit(pos);
-
-            System.out.println("[Raw write" +
-                (hsData ? "" : " (bb)") + "]: length = " +
-                bb.remaining());
-            hd.encodeBuffer(bb, System.out);
-        } catch (IOException e) { }
-    }
-
-    /*
-     * Properly orders the output of the data written to the wrap call.
-     * Only app data goes through here, handshake data goes through
-     * the other writeRecord.
-     *
-     * Shouldn't expect to have an IOException here.
-     *
-     * Return any determined status.
-     */
-    synchronized HandshakeStatus writeRecord(
-            EngineOutputRecord outputRecord, EngineArgs ea,
-            Authenticator authenticator,
-            CipherBox writeCipher) throws IOException {
-
-        /*
-         * If we have data ready to go, output this first before
-         * trying to consume app data.
-         */
-        if (hasOutboundDataInternal()) {
-            HandshakeStatus hss = getOutboundData(ea.netData);
-
-            if (debug != null && Debug.isOn("packet")) {
-                /*
-                 * We could have put the dump in
-                 * OutputRecord.write(OutputStream), but let's actually
-                 * output when it's actually output by the SSLEngine.
-                 */
-                dumpPacket(ea, true);
-            }
-
-            return hss;
-        }
-
-        /*
-         * If we are closed, no more app data can be output.
-         * Only existing handshake data (above) can be obtained.
-         */
-        if (outboundClosed) {
-            throw new IOException("The write side was already closed");
-        }
-
-        outputRecord.write(ea, authenticator, writeCipher);
-
-        if (debug != null && Debug.isOn("packet")) {
-            dumpPacket(ea, false);
-        }
-
-        /*
-         * No way new outbound handshake data got here if we're
-         * locked properly.
-         *
-         * We don't have any status we can return.
-         */
-        return null;
-    }
-
-    /*
-     * We already hold "this" lock, this is the callback from the
-     * outputRecord.write() above.  We already know this
-     * writer can accept more data (outboundClosed == false),
-     * and the closure is sync'd.
-     */
-    void putOutboundData(ByteBuffer bytes) {
-        outboundList.addLast(bytes);
-    }
-
-    /*
-     * This is for the really rare case that someone is writing from
-     * the *InputRecord* before we know what to do with it.
-     */
-    synchronized void putOutboundDataSync(ByteBuffer bytes)
-            throws IOException {
-
-        if (outboundClosed) {
-            throw new IOException("Write side already closed");
-        }
-
-        outboundList.addLast(bytes);
-    }
-
-    /*
-     * Non-synch'd version of this method, called by internals
-     */
-    private boolean hasOutboundDataInternal() {
-        return (outboundList.size() != 0);
-    }
-
-    synchronized boolean hasOutboundData() {
-        return hasOutboundDataInternal();
-    }
-
-    synchronized boolean isOutboundDone() {
-        return outboundClosed && !hasOutboundDataInternal();
-    }
-
-    synchronized void closeOutbound() {
-        outboundClosed = true;
-    }
-
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Tue Jun 02 04:01:04 2015 +0000
@@ -29,6 +29,7 @@
 import java.io.ByteArrayOutputStream;
 import java.security.*;
 import java.util.Locale;
+import java.nio.ByteBuffer;
 
 /**
  * Abstraction for the SSL/TLS hash of all handshake messages that is
@@ -99,6 +100,9 @@
     // For TLS 1.2
     private MessageDigest finMD;
 
+    // Cache for input record handshake hash computation
+    private ByteArrayOutputStream reserve = new ByteArrayOutputStream();
+
     /**
      * Create a new HandshakeHash. needCertificateVerify indicates whether
      * a hash for the certificate verify message is required.
@@ -107,7 +111,106 @@
         clonesNeeded = needCertificateVerify ? 3 : 2;
     }
 
+    void reserve(ByteBuffer input) {
+        if (input.hasArray()) {
+            reserve.write(input.array(),
+                    input.position() + input.arrayOffset(), input.remaining());
+        } else {
+            int inPos = input.position();
+            byte[] holder = new byte[input.remaining()];
+            input.get(holder);
+            input.position(inPos);
+            reserve.write(holder, 0, holder.length);
+        }
+    }
+
+    void reserve(byte[] b, int offset, int len) {
+        reserve.write(b, offset, len);
+    }
+
+    void reload() {
+        if (reserve.size() != 0) {
+            byte[] bytes = reserve.toByteArray();
+            reserve.reset();
+            update(bytes, 0, bytes.length);
+        }
+    }
+
+    void update(ByteBuffer input) {
+
+        // reload if there are reserved messages.
+        reload();
+
+        int inPos = input.position();
+        switch (version) {
+            case 1:
+                md5.update(input);
+                input.position(inPos);
+
+                sha.update(input);
+                input.position(inPos);
+
+                break;
+            default:
+                if (finMD != null) {
+                    finMD.update(input);
+                    input.position(inPos);
+                }
+                if (input.hasArray()) {
+                    data.write(input.array(),
+                            inPos + input.arrayOffset(), input.remaining());
+                } else {
+                    byte[] holder = new byte[input.remaining()];
+                    input.get(holder);
+                    input.position(inPos);
+                    data.write(holder, 0, holder.length);
+                }
+                break;
+        }
+    }
+
+    void update(byte handshakeType, byte[] handshakeBody) {
+
+        // reload if there are reserved messages.
+        reload();
+
+        switch (version) {
+            case 1:
+                md5.update(handshakeType);
+                sha.update(handshakeType);
+
+                md5.update((byte)((handshakeBody.length >> 16) & 0xFF));
+                sha.update((byte)((handshakeBody.length >> 16) & 0xFF));
+                md5.update((byte)((handshakeBody.length >> 8) & 0xFF));
+                sha.update((byte)((handshakeBody.length >> 8) & 0xFF));
+                md5.update((byte)(handshakeBody.length & 0xFF));
+                sha.update((byte)(handshakeBody.length & 0xFF));
+
+                md5.update(handshakeBody);
+                sha.update(handshakeBody);
+                break;
+            default:
+                if (finMD != null) {
+                    finMD.update(handshakeType);
+                    finMD.update((byte)((handshakeBody.length >> 16) & 0xFF));
+                    finMD.update((byte)((handshakeBody.length >> 8) & 0xFF));
+                    finMD.update((byte)(handshakeBody.length & 0xFF));
+                    finMD.update(handshakeBody);
+                }
+                data.write(handshakeType);
+                data.write((byte)((handshakeBody.length >> 16) & 0xFF));
+                data.write((byte)((handshakeBody.length >> 8) & 0xFF));
+                data.write((byte)(handshakeBody.length & 0xFF));
+                data.write(handshakeBody, 0, handshakeBody.length);
+                break;
+        }
+    }
+
     void update(byte[] b, int offset, int len) {
+
+        // reload if there are reserved messages.
+        reload();
+
         switch (version) {
             case 1:
                 md5.update(b, offset, len);
@@ -139,9 +242,15 @@
     void protocolDetermined(ProtocolVersion pv) {
 
         // Do not set again, will ignore
-        if (version != -1) return;
+        if (version != -1) {
+            return;
+        }
 
-        version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
+        if (pv.maybeDTLSProtocol()) {
+            version = pv.compareTo(ProtocolVersion.DTLS12) >= 0 ? 2 : 1;
+        } else {
+            version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
+        }
         switch (version) {
             case 1:
                 // initiate md5, sha and call update on saved array
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Tue Jun 02 04:01:04 2015 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,11 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
-import java.io.InputStream;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 import javax.net.ssl.SSLException;
 
@@ -38,154 +38,104 @@
  * Once a new handshake record arrives, it is buffered in this class until
  * processed by the Handshaker. The buffer may also contain incomplete
  * handshake messages in case the message is split across multiple records.
- * Handshaker.process_record deals with all that. It may also contain
+ * Handshaker.processRecord deals with all that. It may also contain
  * handshake messages larger than the default buffer size (e.g. large
- * certificate messages). The buffer is grown dynamically to handle that
- * (see InputRecord.queueHandshake()).
+ * certificate messages). The buffer is grown dynamically to handle that.
  *
- * Note that the InputRecord used as a buffer here is separate from the
- * AppInStream.r, which is where data from the socket is initially read
- * into. This is because once the initial handshake has been completed,
- * handshake and application data messages may be interleaved arbitrarily
- * and must be processed independently.
+ * Note that this class only handles Handshake messages in TLS format.
+ * DTLS Handshake messages should be converted into TLS format before
+ * calling into this method.
  *
  * @author David Brownell
  */
-public class HandshakeInStream extends InputStream {
 
-    InputRecord r;
+// This class is used to handle plain text handshake messages.
+//
+public final class HandshakeInStream extends ByteArrayInputStream {
 
     /*
      * Construct the stream; we'll be accumulating hashes of the
      * input records using two sets of digests.
      */
-    HandshakeInStream(HandshakeHash handshakeHash) {
-        r = new InputRecord();
-        r.setHandshakeHash(handshakeHash);
+    HandshakeInStream() {
+        super(new byte[0]);     // lazy to alloacte the internal buffer
     }
 
+    //
+    // overridden ByteArrayInputStream methods
+    //
 
-    // overridden InputStream methods
+    @Override
+    public int read(byte[] b) throws IOException {
+        if (super.read(b) != b.length) {
+            throw new SSLException("Unexpected end of handshake data");
+        }
 
-    /*
-     * Return the number of bytes available for read().
-     *
-     * Note that this returns the bytes remaining in the buffer, not
-     * the bytes remaining in the current handshake message.
-     */
-    @Override
-    public int available() {
-        return r.available();
+        return b.length;
     }
 
-    /*
-     * Get a byte of handshake data.
-     */
-    @Override
-    public int read() throws IOException {
-        int n = r.read();
-        if (n == -1) {
-            throw new SSLException("Unexpected end of handshake data");
-        }
-        return n;
-    }
-
-    /*
-     * Get a bunch of bytes of handshake data.
-     */
-    @Override
-    public int read(byte b [], int off, int len) throws IOException {
-        // we read from a ByteArrayInputStream, it always returns the
-        // data in a single read if enough is available
-        int n = r.read(b, off, len);
-        if (n != len) {
-            throw new SSLException("Unexpected end of handshake data");
-        }
-        return n;
-    }
-
-    /*
-     * Skip some handshake data.
-     */
-    @Override
-    public long skip(long n) throws IOException {
-        return r.skip(n);
-    }
-
-    /*
-     * Mark/ reset code, implemented using InputRecord mark/ reset.
-     *
-     * Note that it currently provides only a limited mark functionality
-     * and should be used with care (once a new handshake record has been
-     * read, data that has already been consumed is lost even if marked).
-     */
-
-    @Override
-    public void mark(int readlimit) {
-        r.mark(readlimit);
-    }
-
-    @Override
-    public void reset() throws IOException {
-        r.reset();
-    }
-
-    @Override
-    public boolean markSupported() {
-        return true;
-    }
-
-
-    // handshake management functions
+    //
+    // handshake input stream management functions
+    //
 
     /*
      * Here's an incoming record with handshake data.  Queue the contents;
      * it might be one or more entire messages, complete a message that's
      * partly queued, or both.
      */
-    void incomingRecord(InputRecord in) throws IOException {
-        r.queueHandshake(in);
+    void incomingRecord(ByteBuffer in) throws IOException {
+        int len;
+
+        // Move any unread data to the front of the buffer.
+        if (pos != 0) {
+            len = count - pos;
+            if (len != 0) {
+                System.arraycopy(buf, pos, buf, 0, len);
+            }
+            pos = 0;
+            count = len;
+        }
+
+        // Grow buffer if needed.
+        len = in.remaining() + count;
+        if (buf.length < len) {
+            byte[] newbuf = new byte[len];
+            if (count != 0) {
+                System.arraycopy(buf, 0, newbuf, 0, count);
+            }
+            buf = newbuf;
+        }
+
+        // Append the incoming record to the buffer
+        in.get(buf, count, in.remaining());
+        count = len;
     }
 
-    /*
-     * Hash any data we've consumed but not yet hashed.  Useful mostly
-     * for processing client certificate messages (so we can check the
-     * immediately following cert verify message) and finished messages
-     * (so we can compute our own finished message).
-     */
-    void digestNow() {
-        r.doHashes();
-    }
-
-    /*
-     * Do more than skip that handshake data ... totally ignore it.
-     * The difference is that the data does not get hashed.
-     */
-    void ignore(int n) {
-        r.ignore(n);
-    }
-
-
+    //
     // Message parsing methods
+    //
 
     /*
      * Read 8, 16, 24, and 32 bit SSL integer data types, encoded
      * in standard big-endian form.
      */
-
     int getInt8() throws IOException {
+        verifyLength(1);
         return read();
     }
 
     int getInt16() throws IOException {
+        verifyLength(2);
         return (getInt8() << 8) | getInt8();
     }
 
     int getInt24() throws IOException {
+        verifyLength(3);
         return (getInt8() << 16) | (getInt8() << 8) | getInt8();
     }
 
     int getInt32() throws IOException {
+        verifyLength(4);
         return (getInt8() << 24) | (getInt8() << 16)
              | (getInt8() << 8) | getInt8();
     }
@@ -193,13 +143,12 @@
     /*
      * Read byte vectors with 8, 16, and 24 bit length encodings.
      */
-
     byte[] getBytes8() throws IOException {
         int len = getInt8();
         verifyLength(len);
         byte b[] = new byte[len];
 
-        read(b, 0, len);
+        read(b);
         return b;
     }
 
@@ -208,7 +157,7 @@
         verifyLength(len);
         byte b[] = new byte[len];
 
-        read(b, 0, len);
+        read(b);
         return b;
     }
 
@@ -217,16 +166,14 @@
         verifyLength(len);
         byte b[] = new byte[len];
 
-        read(b, 0, len);
+        read(b);
         return b;
     }
 
     // Is a length greater than available bytes in the record?
     private void verifyLength(int len) throws SSLException {
         if (len > available()) {
-            throw new SSLException(
-                        "Not enough data to fill declared vector size");
+            throw new SSLException("Unexpected end of handshake data");
         }
     }
-
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Tue Jun 02 04:01:04 2015 +0000
@@ -73,24 +73,43 @@
  */
 public abstract class HandshakeMessage {
 
-    HandshakeMessage() { }
+    /* Class and subclass dynamic debugging support */
+    public static final Debug debug = Debug.getInstance("ssl");
 
     // enum HandshakeType:
-    static final byte   ht_hello_request = 0;
-    static final byte   ht_client_hello = 1;
-    static final byte   ht_server_hello = 2;
+    static final byte   ht_hello_request          = 0;      // RFC 5246
+    static final byte   ht_client_hello           = 1;      // RFC 5246
+    static final byte   ht_server_hello           = 2;      // RFC 5246
+    static final byte   ht_hello_verify_request   = 3;      // RFC 6347
+    static final byte   ht_new_session_ticket     = 4;      // RFC 4507
 
-    static final byte   ht_certificate = 11;
-    static final byte   ht_server_key_exchange = 12;
-    static final byte   ht_certificate_request = 13;
-    static final byte   ht_server_hello_done = 14;
-    static final byte   ht_certificate_verify = 15;
-    static final byte   ht_client_key_exchange = 16;
+    static final byte   ht_certificate            = 11;     // RFC 5246
+    static final byte   ht_server_key_exchange    = 12;     // RFC 5246
+    static final byte   ht_certificate_request    = 13;     // RFC 5246
+    static final byte   ht_server_hello_done      = 14;     // RFC 5246
+    static final byte   ht_certificate_verify     = 15;     // RFC 5246
+    static final byte   ht_client_key_exchange    = 16;     // RFC 5246
 
-    static final byte   ht_finished = 20;
+    static final byte   ht_finished               = 20;     // RFC 5246
+    static final byte   ht_certificate_url        = 21;     // RFC 6066
+    static final byte   ht_certificate_status     = 22;     // RFC 6066
+    static final byte   ht_supplemental_data      = 23;     // RFC 4680
 
-    /* Class and subclass dynamic debugging support */
-    public static final Debug debug = Debug.getInstance("ssl");
+    static final byte   ht_not_applicable         = -1;     // N/A
+
+    /*
+     * SSL 3.0 MAC padding constants.
+     * Also used by CertificateVerify and Finished during the handshake.
+     */
+    static final byte[] MD5_pad1 = genPad(0x36, 48);
+    static final byte[] MD5_pad2 = genPad(0x5c, 48);
+
+    static final byte[] SHA_pad1 = genPad(0x36, 40);
+    static final byte[] SHA_pad2 = genPad(0x5c, 40);
+
+    // default constructor
+    HandshakeMessage() {
+    }
 
     /**
      * Utility method to convert a BigInteger to a byte array in unsigned
@@ -109,16 +128,6 @@
         return b;
     }
 
-    /*
-     * SSL 3.0 MAC padding constants.
-     * Also used by CertificateVerify and Finished during the handshake.
-     */
-    static final byte[] MD5_pad1 = genPad(0x36, 48);
-    static final byte[] MD5_pad2 = genPad(0x5c, 48);
-
-    static final byte[] SHA_pad1 = genPad(0x36, 40);
-    static final byte[] SHA_pad2 = genPad(0x5c, 40);
-
     private static byte[] genPad(int b, int count) {
         byte[] padding = new byte[count];
         Arrays.fill(padding, (byte)b);
@@ -141,6 +150,7 @@
         s.write(messageType());
         s.putInt24(len);
         send(s);
+        s.complete();
     }
 
     /*
@@ -199,6 +209,69 @@
 
 }
 
+/*
+ * HelloVerifyRequest ... SERVER --> CLIENT  [DTLS only]
+ *
+ * The definition of HelloVerifyRequest is as follows:
+ *
+ *     struct {
+ *       ProtocolVersion server_version;
+ *       opaque cookie<0..2^8-1>;
+ *     } HelloVerifyRequest;
+ *
+ * For DTLS protocols, once the client has transmitted the ClientHello message,
+ * it expects to see a HelloVerifyRequest from the server.  However, if the
+ * server's message is lost, the client knows that either the ClientHello or
+ * the HelloVerifyRequest has been lost and retransmits. [RFC 6347]
+ */
+static final class HelloVerifyRequest extends HandshakeMessage {
+    ProtocolVersion     protocolVersion;
+    byte[]              cookie;         // 1 to 2^8 - 1 bytes
+
+    HelloVerifyRequest(HelloCookieManager helloCookieManager,
+            ClientHello clientHelloMsg) {
+
+        this.protocolVersion = clientHelloMsg.protocolVersion;
+        this.cookie = helloCookieManager.getCookie(clientHelloMsg);
+    }
+
+    HelloVerifyRequest(
+            HandshakeInStream input, int messageLength) throws IOException {
+
+        this.protocolVersion =
+                ProtocolVersion.valueOf(input.getInt8(), input.getInt8());
+        this.cookie = input.getBytes8();
+
+        // Is it a valid cookie?
+        HelloCookieManager.checkCookie(protocolVersion, cookie);
+    }
+
+    @Override
+    int messageType() {
+        return ht_hello_verify_request;
+    }
+
+    @Override
+    int messageLength() {
+        return 2 + cookie.length;       // 2: the length of protocolVersion
+    }
+
+    @Override
+    void send(HandshakeOutStream hos) throws IOException {
+        hos.putInt8(protocolVersion.major);
+        hos.putInt8(protocolVersion.minor);
+        hos.putBytes8(cookie);
+    }
+
+    @Override
+    void print(PrintStream out) throws IOException {
+        out.println("*** HelloVerifyRequest");
+        if (debug != null && Debug.isOn("verbose")) {
+            out.println("server_version: " + protocolVersion);
+            Debug.println(out, "cookie", cookie);
+        }
+    }
+}
 
 /*
  * ClientHello ... CLIENT --> SERVER
@@ -213,22 +286,31 @@
  */
 static final class ClientHello extends HandshakeMessage {
 
-    ProtocolVersion     protocolVersion;
-    RandomCookie        clnt_random;
-    SessionId           sessionId;
-    private CipherSuiteList    cipherSuites;
-    byte[]              compression_methods;
+    ProtocolVersion             protocolVersion;
+    RandomCookie                clnt_random;
+    SessionId                   sessionId;
+    byte[]                      cookie;                     // DTLS only
+    private CipherSuiteList     cipherSuites;
+    private final boolean       isDTLS;
+    byte[]                      compression_methods;
 
     HelloExtensions extensions = new HelloExtensions();
 
     private final static byte[]  NULL_COMPRESSION = new byte[] {0};
 
     ClientHello(SecureRandom generator, ProtocolVersion protocolVersion,
-            SessionId sessionId, CipherSuiteList cipherSuites) {
+            SessionId sessionId, CipherSuiteList cipherSuites,
+            boolean isDTLS) {
 
+        this.isDTLS = isDTLS;
         this.protocolVersion = protocolVersion;
         this.sessionId = sessionId;
         this.cipherSuites = cipherSuites;
+        if (isDTLS) {
+            this.cookie = new byte[0];
+        } else {
+            this.cookie = null;
+        }
 
         if (cipherSuites.containsEC()) {
             extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
@@ -239,11 +321,21 @@
         compression_methods = NULL_COMPRESSION;
     }
 
-    ClientHello(HandshakeInStream s, int messageLength) throws IOException {
+    ClientHello(HandshakeInStream s,
+            int messageLength, boolean isDTLS) throws IOException {
+
+        this.isDTLS = isDTLS;
+
         protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
         clnt_random = new RandomCookie(s);
         sessionId = new SessionId(s.getBytes8());
         sessionId.checkLength(protocolVersion);
+        if (isDTLS) {
+            cookie = s.getBytes8();
+        } else {
+            cookie = null;
+        }
+
         cipherSuites = new CipherSuiteList(s);
         compression_methods = s.getBytes8();
         if (messageLength() != messageLength) {
@@ -279,6 +371,28 @@
         extensions.add(signatureAlgorithm);
     }
 
+    void addMFLExtension(int maximumPacketSize) {
+        HelloExtension maxFragmentLength =
+                new MaxFragmentLengthExtension(maximumPacketSize);
+        extensions.add(maxFragmentLength);
+    }
+
+    void updateHelloCookie(MessageDigest cookieDigest) {
+        //
+        // Just use HandshakeOutStream to compute the hello verify cookie.
+        // Not actually used to output handshake message records.
+        //
+        HandshakeOutStream hos = new HandshakeOutStream(null);
+
+        try {
+            send(hos, false);    // Do not count hello verify cookie.
+        } catch (IOException ioe) {
+            // unlikely to happen
+        }
+
+        cookieDigest.update(hos.toByteArray());
+    }
+
     @Override
     int messageType() { return ht_client_hello; }
 
@@ -290,6 +404,7 @@
          */
         return (2 + 32 + 1 + 2 + 1
             + sessionId.length()                /* ... + variable parts */
+            + (isDTLS ? (1 + cookie.length) : 0)
             + (cipherSuites.size() * 2)
             + compression_methods.length)
             + extensions.length();
@@ -297,13 +412,7 @@
 
     @Override
     void send(HandshakeOutStream s) throws IOException {
-        s.putInt8(protocolVersion.major);
-        s.putInt8(protocolVersion.minor);
-        clnt_random.send(s);
-        s.putBytes8(sessionId.getId());
-        cipherSuites.send(s);
-        s.putBytes8(compression_methods);
-        extensions.send(s);
+        send(s, true);  // Count hello verify cookie.
     }
 
     @Override
@@ -317,6 +426,10 @@
             s.print("Session ID:  ");
             s.println(sessionId);
 
+            if (isDTLS) {
+                Debug.println(s, "cookie", cookie);
+            }
+
             s.println("Cipher Suites: " + cipherSuites);
 
             Debug.println(s, "Compression Methods", compression_methods);
@@ -324,6 +437,21 @@
             s.println("***");
         }
     }
+
+    private void send(HandshakeOutStream s,
+            boolean computeCookie) throws IOException {
+        s.putInt8(protocolVersion.major);
+        s.putInt8(protocolVersion.minor);
+        clnt_random.send(s);
+        s.putBytes8(sessionId.getId());
+        if (isDTLS && computeCookie) {
+            s.putBytes8(cookie);
+        }
+        cipherSuites.send(s);
+        s.putBytes8(compression_methods);
+        extensions.send(s);
+    }
+
 }
 
 /*
@@ -740,7 +868,7 @@
         setValues(obj);
 
         Signature sig;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             this.preferableSignatureAlgorithm = signAlgorithm;
             sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
@@ -801,7 +929,7 @@
                                              new BigInteger(1, dh_g)));
 
         // read the signature and hash algorithm
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             int hash = input.getInt8();         // hash algorithm
             int signature = input.getInt8();    // signature algorithm
 
@@ -834,7 +962,7 @@
 
         Signature sig;
         String algorithm = publicKey.getAlgorithm();
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             sig = JsseJce.getSignature(
                         preferableSignatureAlgorithm.getAlgorithmName());
         } else {
@@ -914,7 +1042,7 @@
         temp += dh_Ys.length;
 
         if (signature != null) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 temp += SignatureAndHashAlgorithm.sizeInRecord();
             }
 
@@ -934,7 +1062,7 @@
         s.putBytes16(dh_Ys);
 
         if (signature != null) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 s.putInt8(preferableSignatureAlgorithm.getHashValue());
                 s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
             }
@@ -959,7 +1087,7 @@
             if (signature == null) {
                 s.println("Anonymous");
             } else {
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     s.println("Signature Algorithm " +
                         preferableSignatureAlgorithm.getAlgorithmName());
                 }
@@ -1021,7 +1149,7 @@
         }
 
         Signature sig;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             this.preferableSignatureAlgorithm = signAlgorithm;
             sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
@@ -1084,7 +1212,7 @@
         }
 
         // read the signature and hash algorithm
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             int hash = input.getInt8();         // hash algorithm
             int signature = input.getInt8();    // signature algorithm
 
@@ -1105,7 +1233,7 @@
 
         // verify the signature
         Signature sig;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             sig = JsseJce.getSignature(
                         preferableSignatureAlgorithm.getAlgorithmName());
         } else {
@@ -1157,7 +1285,7 @@
         int sigLen = 0;
         if (signatureBytes != null) {
             sigLen = 2 + signatureBytes.length;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 sigLen += SignatureAndHashAlgorithm.sizeInRecord();
             }
         }
@@ -1172,7 +1300,7 @@
         s.putBytes8(pointBytes);
 
         if (signatureBytes != null) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 s.putInt8(preferableSignatureAlgorithm.getHashValue());
                 s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
             }
@@ -1189,7 +1317,7 @@
             if (signatureBytes == null) {
                 s.println("Anonymous");
             } else {
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     s.println("Signature Algorithm " +
                             preferableSignatureAlgorithm.getAlgorithmName());
                 }
@@ -1315,7 +1443,7 @@
         this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC;
 
         // Use supported_signature_algorithms for TLS 1.2 or later.
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             if (signAlgs == null || signAlgs.isEmpty()) {
                 throw new SSLProtocolException(
                         "No supported signature algorithms");
@@ -1339,7 +1467,7 @@
         types = input.getBytes8();
 
         // Read the supported_signature_algorithms for TLS 1.2 or later.
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             algorithmsLen = input.getInt16();
             if (algorithmsLen < 2) {
                 throw new SSLProtocolException(
@@ -1406,7 +1534,7 @@
     int messageLength() {
         int len = 1 + types.length + 2;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             len += algorithmsLen + 2;
         }
 
@@ -1423,7 +1551,7 @@
         output.putBytes8(types);
 
         // put supported_signature_algorithms
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             output.putInt16(algorithmsLen);
             for (SignatureAndHashAlgorithm algorithm : algorithms) {
                 output.putInt8(algorithm.getHashValue());      // hash
@@ -1478,7 +1606,7 @@
             }
             s.println();
 
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 StringBuilder sb = new StringBuilder();
                 boolean opened = false;
                 for (SignatureAndHashAlgorithm signAlg : algorithms) {
@@ -1576,7 +1704,7 @@
 
         String algorithm = privateKey.getAlgorithm();
         Signature sig = null;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             this.preferableSignatureAlgorithm = signAlgorithm;
             sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
@@ -1598,7 +1726,7 @@
         this.protocolVersion = protocolVersion;
 
         // read the signature and hash algorithm
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             int hashAlg = input.getInt8();         // hash algorithm
             int signAlg = input.getInt8();         // signature algorithm
 
@@ -1634,7 +1762,7 @@
             SecretKey masterSecret) throws GeneralSecurityException {
         String algorithm = publicKey.getAlgorithm();
         Signature sig = null;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             sig = JsseJce.getSignature(
                         preferableSignatureAlgorithm.getAlgorithmName());
         } else {
@@ -1676,11 +1804,11 @@
             throws SignatureException {
 
         if (algorithm.equals("RSA")) {
-            if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
+            if (!protocolVersion.useTLS12PlusSpec()) {  // TLS1.1-
                 MessageDigest md5Clone = handshakeHash.getMD5Clone();
                 MessageDigest shaClone = handshakeHash.getSHAClone();
 
-                if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
+                if (!protocolVersion.useTLS10PlusSpec()) {  // SSLv3
                     updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
                     updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
                 }
@@ -1692,10 +1820,10 @@
                 sig.update(handshakeHash.getAllHandshakeMessages());
             }
         } else { // DSA, ECDSA
-            if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
+            if (!protocolVersion.useTLS12PlusSpec()) {  // TLS1.1-
                 MessageDigest shaClone = handshakeHash.getSHAClone();
 
-                if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
+                if (!protocolVersion.useTLS10PlusSpec()) {  // SSLv3
                     updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
                 }
 
@@ -1811,7 +1939,7 @@
     int messageLength() {
         int temp = 2;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             temp += SignatureAndHashAlgorithm.sizeInRecord();
         }
 
@@ -1820,7 +1948,7 @@
 
     @Override
     void send(HandshakeOutStream s) throws IOException {
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             s.putInt8(preferableSignatureAlgorithm.getHashValue());
             s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
         }
@@ -1833,7 +1961,7 @@
         s.println("*** CertificateVerify");
 
         if (debug != null && Debug.isOn("verbose")) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 s.println("Signature Algorithm " +
                         preferableSignatureAlgorithm.getAlgorithmName());
             }
@@ -1899,7 +2027,7 @@
             CipherSuite cipherSuite) throws IOException {
         this.protocolVersion = protocolVersion;
         this.cipherSuite = cipherSuite;
-        int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36;
+        int msgLen = protocolVersion.useTLS10PlusSpec() ?  12 : 36;
         verifyData = new byte[msgLen];
         input.read(verifyData);
     }
@@ -1932,7 +2060,7 @@
             throw new RuntimeException("Invalid sender: " + sender);
         }
 
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             // TLS 1.0+
             try {
                 byte [] seed;
@@ -1940,14 +2068,14 @@
                 PRF prf;
 
                 // Get the KeyGenerator alg and calculate the seed.
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
-                    // TLS 1.2
+                if (protocolVersion.useTLS12PlusSpec()) {
+                    // TLS 1.2+ or DTLS 1.2+
                     seed = handshakeHash.getFinishedHash();
 
                     prfAlg = "SunTls12Prf";
                     prf = cipherSuite.prfAlg;
                 } else {
-                    // TLS 1.0/1.1
+                    // TLS 1.0/1.1, DTLS 1.0
                     MessageDigest md5Clone = handshakeHash.getMD5Clone();
                     MessageDigest shaClone = handshakeHash.getSHAClone();
                     seed = new byte[36];
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Tue Jun 02 04:01:04 2015 +0000
@@ -23,10 +23,9 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
-import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
 /**
@@ -40,197 +39,113 @@
  *
  * @author  David Brownell
  */
-public class HandshakeOutStream extends OutputStream {
+public class HandshakeOutStream extends ByteArrayOutputStream {
 
-    private SSLSocketImpl socket;
-    private SSLEngineImpl engine;
+    OutputRecord outputRecord;      // May be null if not actually used to
+                                    // output handshake message records.
 
-    OutputRecord r;
-
-    HandshakeOutStream(ProtocolVersion protocolVersion,
-            ProtocolVersion helloVersion, HandshakeHash handshakeHash,
-            SSLSocketImpl socket) {
-        this.socket = socket;
-        r = new OutputRecord(Record.ct_handshake);
-        init(protocolVersion, helloVersion, handshakeHash);
+    HandshakeOutStream(OutputRecord outputRecord) {
+        super();
+        this.outputRecord = outputRecord;
     }
 
-    HandshakeOutStream(ProtocolVersion protocolVersion,
-            ProtocolVersion helloVersion, HandshakeHash handshakeHash,
-            SSLEngineImpl engine) {
-        this.engine = engine;
-        r = new EngineOutputRecord(Record.ct_handshake, engine);
-        init(protocolVersion, helloVersion, handshakeHash);
+    // Complete a handshakin message writing. Called by HandshakeMessage.
+    void complete() throws IOException {
+        if (size() < 4) {       // 4: handshake message header size
+            // internal_error alert will be triggered
+            throw new RuntimeException("handshake message is not available");
+        }
+
+        // outputRecord cannot be null
+        outputRecord.encodeHandshake(buf, 0, count);
+
+        // reset the byte array output stream
+        reset();
     }
 
-    private void init(ProtocolVersion protocolVersion,
-            ProtocolVersion helloVersion, HandshakeHash handshakeHash) {
-        r.setVersion(protocolVersion);
-        r.setHelloVersion(helloVersion);
-        r.setHandshakeHash(handshakeHash);
-    }
+    //
+    // overridden ByteArrayOutputStream methods
+    //
 
-
-    /*
-     * Update the handshake data hashes ... mostly for use after a
-     * client cert has been sent, so the cert verify message can be
-     * constructed correctly yet without forcing extra I/O.  In all
-     * other cases, automatic hash calculation suffices.
-     */
-    void doHashes() {
-        r.doHashes();
-    }
-
-    /*
-     * Write some data out onto the stream ... buffers as much as possible.
-     * Hashes are updated automatically if something gets flushed to the
-     * network (e.g. a big cert message etc).
-     */
     @Override
-    public void write(byte buf[], int off, int len) throws IOException {
-        while (len > 0) {
-            int howmuch = Math.min(len, r.availableDataBytes());
-
-            if (howmuch == 0) {
-                flush();
-            } else {
-                r.write(buf, off, howmuch);
-                off += howmuch;
-                len -= howmuch;
-            }
-        }
-    }
-
-    /*
-     * write-a-byte
-     */
-    @Override
-    public void write(int i) throws IOException {
-        if (r.availableDataBytes() < 1) {
-            flush();
-        }
-        r.write(i);
+    public void write(byte[] b, int off, int len) {
+        // The maximum fragment size is 24 bytes.
+        checkOverflow(len, Record.OVERFLOW_OF_INT24);
+        super.write(b, off, len);
     }
 
     @Override
     public void flush() throws IOException {
-        if (socket != null) {
-            try {
-                socket.writeRecord(r);
-            } catch (IOException e) {
-                // Had problems writing; check if there was an
-                // alert from peer. If alert received, waitForClose
-                // will throw an exception for the alert
-                socket.waitForClose(true);
-
-                // No alert was received, just rethrow exception
-                throw e;
-            }
-        } else {  // engine != null
-            /*
-             * Even if record might be empty, flush anyway in case
-             * there is a finished handshake message that we need
-             * to queue.
-             */
-            engine.writeRecord((EngineOutputRecord)r);
-        }
+        outputRecord.flush();
     }
 
-    /*
-     * Tell the OutputRecord that a finished message was
-     * contained either in this record or the one immeiately
-     * preceding it.  We need to reliably pass back notifications
-     * that a finish message occurred.
-     */
-    void setFinishedMsg() {
-        assert(socket == null);
-
-        ((EngineOutputRecord)r).setFinishedMsg();
-    }
+    //
+    // handshake output stream management functions
+    //
 
     /*
      * Put integers encoded in standard 8, 16, 24, and 32 bit
      * big endian formats. Note that OutputStream.write(int) only
      * writes the least significant 8 bits and ignores the rest.
      */
-
     void putInt8(int i) throws IOException {
         checkOverflow(i, Record.OVERFLOW_OF_INT08);
-        r.write(i);
+        super.write(i);
     }
 
     void putInt16(int i) throws IOException {
         checkOverflow(i, Record.OVERFLOW_OF_INT16);
-        if (r.availableDataBytes() < 2) {
-            flush();
-        }
-        r.write(i >> 8);
-        r.write(i);
+        super.write(i >> 8);
+        super.write(i);
     }
 
     void putInt24(int i) throws IOException {
         checkOverflow(i, Record.OVERFLOW_OF_INT24);
-        if (r.availableDataBytes() < 3) {
-            flush();
-        }
-        r.write(i >> 16);
-        r.write(i >> 8);
-        r.write(i);
-    }
-
-    void putInt32(int i) throws IOException {
-        if (r.availableDataBytes() < 4) {
-            flush();
-        }
-        r.write(i >> 24);
-        r.write(i >> 16);
-        r.write(i >> 8);
-        r.write(i);
+        super.write(i >> 16);
+        super.write(i >> 8);
+        super.write(i);
     }
 
     /*
      * Put byte arrays with length encoded as 8, 16, 24 bit
      * integers in big-endian format.
      */
-    void putBytes8(byte b[]) throws IOException {
+    void putBytes8(byte[] b) throws IOException {
         if (b == null) {
             putInt8(0);
-            return;
         } else {
-            checkOverflow(b.length, Record.OVERFLOW_OF_INT08);
+            putInt8(b.length);
+            super.write(b, 0, b.length);
         }
-        putInt8(b.length);
-        write(b, 0, b.length);
     }
 
     public void putBytes16(byte b[]) throws IOException {
         if (b == null) {
             putInt16(0);
-            return;
         } else {
-            checkOverflow(b.length, Record.OVERFLOW_OF_INT16);
+            putInt16(b.length);
+            super.write(b, 0, b.length);
         }
-        putInt16(b.length);
-        write(b, 0, b.length);
     }
 
     void putBytes24(byte b[]) throws IOException {
         if (b == null) {
             putInt24(0);
-            return;
         } else {
-            checkOverflow(b.length, Record.OVERFLOW_OF_INT24);
+            putInt24(b.length);
+            super.write(b, 0, b.length);
         }
-        putInt24(b.length);
-        write(b, 0, b.length);
     }
 
-    private void checkOverflow(int length, int overflow) {
-        if (length >= overflow) {
+    /*
+     * Does the specified length overflow the limitation?
+     */
+    private static void checkOverflow(int length, int limit) {
+        if (length >= limit) {
             // internal_error alert will be triggered
             throw new RuntimeException(
                     "Field length overflow, the field length (" +
-                    length + ") should be less than " + overflow);
+                    length + ") should be less than " + limit);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeStateManager.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,925 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.util.LinkedList;
+import java.util.HashMap;
+import javax.net.ssl.SSLProtocolException;
+
+import sun.security.ssl.HandshakeMessage.*;
+
+import static sun.security.ssl.CipherSuite.KeyExchange;
+import static sun.security.ssl.CipherSuite.KeyExchange.*;
+import static sun.security.ssl.HandshakeStateManager.HandshakeState.*;
+import static sun.security.ssl.HandshakeMessage.*;
+
+/*
+ * Handshake state manager.
+ *
+ * Messages flow for a full handshake:
+ *
+ *      -                                                         -
+ *      |          HelloRequest       (No.0, RFC 5246) [*]        |
+ *      |     <--------------------------------------------       |
+ *      |                                                         |
+ *      |          ClientHello        (No.1, RFC 5246)            |
+ *      |     -------------------------------------------->       |
+ *      |                                                         |
+ *      |   -      HelloVerifyRequest (No.3, RFC 6347)      -     |
+ *      | D | <-------------------------------------------- | D   |
+ *      | T |                                               | T   |
+ *      | L |      ClientHello        (No.1, RFC 5246)      | L   |
+ *      | S | --------------------------------------------> | S   |
+ *      |   -                                               -     |
+ *      |                                                         |
+ *   C  |          ServerHello        (No.2, RFC 5246)            |  S
+ *   L  |          SupplementalData   (No.23, RFC4680) [*]        |  E
+ *   I  |          Certificate        (No.11, RFC 5246) [*]       |  R
+ *   E  |          CertificateStatus  (No.22, RFC 6066) [*]       |  V
+ *   N  |          ServerKeyExchange  (No.12, RFC 5246) [*]       |  E
+ *   T  |          CertificateRequest (No.13, RFC 5246) [*]       |  R
+ *      |          ServerHelloDone    (No.14, RFC 5246)           |
+ *      |     <--------------------------------------------       |
+ *      |                                                         |
+ *      |          SupplementalData   (No.23, RFC4680) [*]        |
+ *      |          Certificate        (No.11, RFC 5246) [*] Or    |
+ *      |              CertificateURL (No.21, RFC6066) [*]        |
+ *      |          ClientKeyExchange  (No.16, RFC 5246)           |
+ *      |          CertificateVerify  (No.15, RFC 5246) [*]       |
+ *      |          [ChangeCipherSpec] (RFC 5246)                  |
+ *      |          Finished           (No.20, RFC 5246)           |
+ *      |     -------------------------------------------->       |
+ *      |                                                         |
+ *      |          NewSessionTicket   (No.4, RFC4507) [*]         |
+ *      |          [ChangeCipherSpec] (RFC 5246)                  |
+ *      |          Finished           (No.20, RFC 5246)           |
+ *      |     <--------------------------------------------       |
+ *      -                                                         -
+ * [*] Indicates optional or situation-dependent messages that are not
+ * always sent.
+ *
+ * Message flow for an abbreviated handshake:
+ *      -                                                         -
+ *      |          ClientHello        (No.1, RFC 5246)            |
+ *      |     -------------------------------------------->       |
+ *      |                                                         |
+ *   C  |          ServerHello        (No.2, RFC 5246)            |  S
+ *   L  |          NewSessionTicket   (No.4, RFC4507) [*]         |  E
+ *   I  |          [ChangeCipherSpec] (RFC 5246)                  |  R
+ *   E  |          Finished           (No.20, RFC 5246)           |  V
+ *   N  |     <--------------------------------------------       |  E
+ *   T  |                                                         |  R
+ *      |          [ChangeCipherSpec] (RFC 5246)                  |
+ *      |          Finished           (No.20, RFC 5246)           |
+ *      |     -------------------------------------------->       |
+ *      -                                                         -
+ *
+ *
+ * State machine of handshake states:
+ *
+ *                   +--------------+
+ *      START -----> | HelloRequest |
+ *        |          +--------------+
+ *        |               |
+ *        v               v
+ *     +---------------------+   -->  +---------------------+
+ *     |    ClientHello      |        | HelloVerifyRequest  |
+ *     +---------------------+   <--  +---------------------+
+ *               |
+ *               |
+ * =========================================================================
+ *               |
+ *               v
+ *     +---------------------+
+ *     |    ServerHello      |  ----------------------------------+------+
+ *     +---------------------+  -->  +-------------------------+  |      |
+ *                    |              | Server SupplementalData |  |      |
+ *                    |              +-------------------------+  |      |
+ *                    |                |                          |      |
+ *                    v                v                          |      |
+ *                +---------------------+                         |      |
+ *         +----  | Server Certificate  |                         |      |
+ *         |      +---------------------+                         |      |
+ *         |          |                                           |      |
+ *         |          |   +--------------------+                  |      |
+ *         |          +-> | CertificateStatus  |                  |      |
+ *         |          |   +--------------------+                  v      |
+ *         |          |      |          |     +--------------------+     |
+ *         |          v      v          +-->  | ServerKeyExchange  |     |
+ *         |  +---------------------+   |     +--------------------+     |
+ *         |  | CertificateRequest  |   |         |                      |
+ *         |  +---------------------+ <-+---------+                      |
+ *         |            |               |         |                      |
+ *         v            v               |         |                      |
+ *     +---------------------+  <-------+         |                      |
+ *     |  ServerHelloDone    |  <-----------------+                      |
+ *     +---------------------+                                           |
+ *       |         |                                                     |
+ *       |         |                                                     |
+ *       |         |                                                     |
+ * =========================================================================
+ *       |         |                                                     |
+ *       |         v                                                     |
+ *       |   +-------------------------+                                 |
+ *       |   | Client SupplementalData | --------------+                 |
+ *       |   +-------------------------+               |                 |
+ *       |             |                               |                 |
+ *       |             v                               |                 |
+ *       |   +--------------------+                    |                 |
+ *       +-> | Client Certificate | ALT.               |                 |
+ *       |   +--------------------+----------------+   |                 |
+ *       |                        | CertificateURL |   |                 |
+ *       |                        +----------------+   |                 |
+ *       v                                             |                 |
+ *     +-------------------+  <------------------------+                 |
+ *     | ClientKeyExchange |                                             |
+ *     +-------------------+                                             |
+ *          |           |                                                |
+ *          |           v                                                |
+ *          |      +-------------------+                                 |
+ *          |      | CertificateVerify |                                 |
+ *          |      +-------------------+                                 |
+ *          |          |                                                 |
+ *          v          v                                                 |
+ *     +-------------------------+                                       |
+ *     | Client ChangeCipherSpec |  <---------------+                    |
+ *     +-------------------------+                  |                    |
+ *               |                                  |                    |
+ *               v                                  |                    |
+ *     +-----------------+  (abbreviated)           |                    |
+ *     | Client Finished |  -------------> END      |                    |
+ *     +-----------------+  (Abbreviated handshake) |                    |
+ *                      |                           |                    |
+ *                      | (full)                    |                    |
+ *                      |                           |                    |
+ * ================================                 |                    |
+ *                      |                           |                    |
+ *                      |                   ================================
+ *                      |                           |                    |
+ *                      v                           |                    |
+ *                 +------------------+             |    (abbreviated)   |
+ *                 | NewSessionTicket | <--------------------------------+
+ *                 +------------------+             |                    |
+ *                      |                           |                    |
+ *                      v                           |                    |
+ *     +-------------------------+                  |    (abbreviated)   |
+ *     | Server ChangeCipherSpec | <-------------------------------------+
+ *     +-------------------------+                  |
+ *               |                                  |
+ *               v                                  |
+ *     +-----------------+    (abbreviated)         |
+ *     | Server Finished | -------------------------+
+ *     +-----------------+
+ *            | (full)
+ *            v
+ *        END (Full handshake)
+ *
+ *
+ * The scenarios of the use of this class:
+ * 1. Create an instance of HandshakeStateManager during the initializtion
+ *    handshake.
+ * 2. If receiving a handshake message, call HandshakeStateManager.check()
+ *    to make sure that the message is of the expected handshake type.  And
+ *    then call HandshakeStateManager.update() in case handshake states may
+ *    be impacted by this new incoming handshake message.
+ * 3. On delivering a handshake message, call HandshakeStateManager.update()
+ *    in case handshake states may by thie new outgoing handshake message.
+ * 4. On receiving and delivering ChangeCipherSpec message, call
+ *    HandshakeStateManager.changeCipherSpec() to check the present sequence
+ *    of this message, and update the states if necessary.
+ */
+final class HandshakeStateManager {
+    // upcoming handshake states.
+    private LinkedList<HandshakeState> upcomingStates;
+    private LinkedList<HandshakeState> alternatives;
+
+    private boolean isDTLS;
+
+    private final static boolean debugIsOn;
+
+    private final static HashMap<Byte, String> handshakeTypes;
+
+    static {
+        debugIsOn = (Handshaker.debug != null) &&
+                Debug.isOn("handshake") && Debug.isOn("verbose");
+        handshakeTypes = new HashMap<>(15);
+
+        handshakeTypes.put(ht_hello_request,            "hello_request");
+        handshakeTypes.put(ht_client_hello,             "client_hello");
+        handshakeTypes.put(ht_server_hello,             "server_hello");
+        handshakeTypes.put(ht_hello_verify_request,     "hello_verify_request");
+        handshakeTypes.put(ht_new_session_ticket,       "session_ticket");
+        handshakeTypes.put(ht_certificate,              "certificate");
+        handshakeTypes.put(ht_server_key_exchange,      "server_key_exchange");
+        handshakeTypes.put(ht_certificate_request,      "certificate_request");
+        handshakeTypes.put(ht_server_hello_done,        "server_hello_done");
+        handshakeTypes.put(ht_certificate_verify,       "certificate_verify");
+        handshakeTypes.put(ht_client_key_exchange,      "client_key_exchange");
+        handshakeTypes.put(ht_finished,                 "finished");
+        handshakeTypes.put(ht_certificate_url,          "certificate_url");
+        handshakeTypes.put(ht_certificate_status,       "certificate_status");
+        handshakeTypes.put(ht_supplemental_data,        "supplemental_data");
+    }
+
+    HandshakeStateManager(boolean isDTLS) {
+        this.upcomingStates = new LinkedList<>();
+        this.alternatives = new LinkedList<>();
+        this.isDTLS = isDTLS;
+    }
+
+    //
+    // enumation of handshake type
+    //
+    static enum HandshakeState {
+        HS_HELLO_REQUEST(
+                "hello_request",
+                HandshakeMessage.ht_hello_request),
+        HS_CLIENT_HELLO(
+                "client_hello",
+                HandshakeMessage.ht_client_hello),
+        HS_HELLO_VERIFY_REQUEST(
+                "hello_verify_request",
+                HandshakeMessage.ht_hello_verify_request),
+        HS_SERVER_HELLO(
+                "server_hello",
+                HandshakeMessage.ht_server_hello),
+        HS_SERVER_SUPPLEMENTAL_DATA(
+                "server supplemental_data",
+                HandshakeMessage.ht_supplemental_data, true),
+        HS_SERVER_CERTIFICATE(
+                "server certificate",
+                HandshakeMessage.ht_certificate),
+        HS_CERTIFICATE_STATUS(
+                "certificate_status",
+                HandshakeMessage.ht_certificate_status, true),
+        HS_SERVER_KEY_EXCHANGE(
+                "server_key_exchange",
+                HandshakeMessage.ht_server_key_exchange, true),
+        HS_CERTIFICATE_REQUEST(
+                "certificate_request",
+                HandshakeMessage.ht_certificate_request, true),
+        HS_SERVER_HELLO_DONE(
+                "server_hello_done",
+                HandshakeMessage.ht_server_hello_done),
+        HS_CLIENT_SUPPLEMENTAL_DATA(
+                "client supplemental_data",
+                HandshakeMessage.ht_supplemental_data, true),
+        HS_CLIENT_CERTIFICATE(
+                "client certificate",
+                HandshakeMessage.ht_certificate, true),
+        HS_CERTIFICATE_URL(
+                "certificate_url",
+                HandshakeMessage.ht_certificate_url, true),
+        HS_CLIENT_KEY_EXCHANGE(
+                "client_key_exchange",
+                HandshakeMessage.ht_client_key_exchange),
+        HS_CERTIFICATE_VERIFY(
+                "certificate_verify",
+                HandshakeMessage.ht_certificate_verify, true),
+        HS_CLIENT_CHANGE_CIPHER_SPEC(
+                "client change_cipher_spec",
+                HandshakeMessage.ht_not_applicable),
+        HS_CLEINT_FINISHED(
+                "client finished",
+                HandshakeMessage.ht_finished),
+        HS_NEW_SESSION_TICKET(
+                "session_ticket",
+                HandshakeMessage.ht_new_session_ticket),
+        HS_SERVER_CHANGE_CIPHER_SPEC(
+                "server change_cipher_spec",
+                HandshakeMessage.ht_not_applicable),
+        HS_SERVER_FINISHDE(
+                "server finished",
+                HandshakeMessage.ht_finished);
+
+        final String description;
+        final byte handshakeType;
+        final boolean isOptional;
+
+        HandshakeState(String description, byte handshakeType) {
+            this.description = description;
+            this.handshakeType = handshakeType;
+            this.isOptional = false;
+        }
+
+        HandshakeState(String description,
+                byte handshakeType, boolean isOptional) {
+
+            this.description = description;
+            this.handshakeType = handshakeType;
+            this.isOptional = isOptional;
+        }
+
+        public String toString() {
+            return description + "[" + handshakeType + "]" +
+                    (isOptional ? "(optional)" : "");
+        }
+    }
+
+    boolean isEmpty() {
+        return upcomingStates.isEmpty();
+    }
+
+    void check(byte handshakeType) throws SSLProtocolException {
+        String exceptionMsg =
+                 "Handshake message sequence violation, " + handshakeType;
+
+        if (debugIsOn) {
+            System.out.println(
+                    "check handshake state: " + toString(handshakeType));
+        }
+
+        if (upcomingStates.isEmpty()) {
+            // Is it a kickstart message?
+            if ((handshakeType != HandshakeMessage.ht_hello_request) &&
+                (handshakeType != HandshakeMessage.ht_client_hello)) {
+
+                throw new SSLProtocolException(
+                    "Handshake message sequence violation, " + handshakeType);
+            }
+
+            // It is a kickstart message.
+            return;
+        }
+
+        // Ignore the checking for HelloRequest messages as they are
+        // may be sent by the server at any time.
+        if (handshakeType == HandshakeMessage.ht_hello_request) {
+            return;
+        }
+
+        for (HandshakeState handshakeState : upcomingStates) {
+            if (handshakeState.handshakeType == handshakeType) {
+                // It's the expected next handshake type.
+                return;
+            }
+
+            if (handshakeState.isOptional) {
+                continue;
+            } else {
+                for (HandshakeState alternative : alternatives) {
+                    if (alternative.handshakeType == handshakeType) {
+                        return;
+                    }
+
+                    if (alternative.isOptional) {
+                        continue;
+                    } else {
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+                }
+            }
+
+            throw new SSLProtocolException(exceptionMsg);
+        }
+
+        // Not an expected Handshake message.
+        throw new SSLProtocolException(
+                "Handshake message sequence violation, " + handshakeType);
+    }
+
+    void update(HandshakeMessage handshakeMessage,
+            boolean isAbbreviated) throws SSLProtocolException {
+
+        byte handshakeType = (byte)handshakeMessage.messageType();
+        String exceptionMsg =
+                 "Handshake message sequence violation, " + handshakeType;
+
+        if (debugIsOn) {
+            System.out.println(
+                    "update handshake state: " + toString(handshakeType));
+        }
+
+        boolean hasPresentState = false;
+        switch (handshakeType) {
+        case HandshakeMessage.ht_hello_request:
+            //
+            // State machine:
+            //     PRESENT: START
+            //        TO  : ClientHello
+            //
+
+            // No old state to update.
+
+            // Add the upcoming states.
+            if (!upcomingStates.isEmpty()) {
+                // A ClientHello message should be followed.
+                upcomingStates.add(HS_CLIENT_HELLO);
+
+            }   // Otherwise, ignore this HelloRequest message.
+
+            break;
+
+        case HandshakeMessage.ht_client_hello:
+            //
+            // State machine:
+            //     PRESENT: START
+            //              HS_CLIENT_HELLO
+            //        TO  : HS_HELLO_VERIFY_REQUEST (DTLS)
+            //              HS_SERVER_HELLO
+            //
+
+            // Check and update the present state.
+            if (!upcomingStates.isEmpty()) {
+                // The current state should be HS_CLIENT_HELLO.
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState != HS_CLIENT_HELLO) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }
+            }
+
+            // Add the upcoming states.
+            ClientHello clientHello = (ClientHello)handshakeMessage;
+            if (isDTLS) {
+                // Is it an initial ClientHello message?
+                if (clientHello.cookie == null ||
+                        clientHello.cookie.length == 0) {
+                    // Is it an abbreviated handshake?
+                    if (clientHello.sessionId.length() != 0) {
+                        // A HelloVerifyRequest message or a ServerHello
+                        // message may follow the abbreviated session
+                        // resuming handshake request.
+                        upcomingStates.add(HS_HELLO_VERIFY_REQUEST);
+                        alternatives.add(HS_SERVER_HELLO);
+                    } else {
+                        // A HelloVerifyRequest message should follow
+                        // the initial ClientHello message.
+                        upcomingStates.add(HS_HELLO_VERIFY_REQUEST);
+                    }
+                } else {
+                    // A HelloVerifyRequest may be followed if the cookie
+                    // cannot be verified.
+                    upcomingStates.add(HS_SERVER_HELLO);
+                    alternatives.add(HS_HELLO_VERIFY_REQUEST);
+                }
+            } else {
+                upcomingStates.add(HS_SERVER_HELLO);
+            }
+
+            break;
+
+        case HandshakeMessage.ht_hello_verify_request:
+            //
+            // State machine:
+            //     PRESENT: HS_HELLO_VERIFY_REQUEST
+            //        TO  : HS_CLIENT_HELLO
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            if (!upcomingStates.isEmpty()) {
+                // The current state should be HS_HELLO_VERIFY_REQUEST.
+                HandshakeState handshakeState = upcomingStates.pop();
+                HandshakeState alternative = null;
+                if (!alternatives.isEmpty()) {
+                    alternative = alternatives.pop();
+                }
+
+                if ((handshakeState != HS_HELLO_VERIFY_REQUEST) &&
+                        (alternative != HS_HELLO_VERIFY_REQUEST)) {
+
+                    throw new SSLProtocolException(exceptionMsg);
+                }
+            } else {
+                // No present state.
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // Add the upcoming states.
+            upcomingStates.add(HS_CLIENT_HELLO);
+
+            break;
+
+        case HandshakeMessage.ht_server_hello:
+            //
+            // State machine:
+            //     PRESENT: HS_SERVER_HELLO
+            //        TO  :
+            //          Full handshake state stacks
+            //              (ServerHello Flight)
+            //              HS_SERVER_SUPPLEMENTAL_DATA [optional]
+            //          --> HS_SERVER_CERTIFICATE [optional]
+            //          --> HS_CERTIFICATE_STATUS [optional]
+            //          --> HS_SERVER_KEY_EXCHANGE [optional]
+            //          --> HS_CERTIFICATE_REQUEST [optional]
+            //          --> HS_SERVER_HELLO_DONE
+            //              (Client ClientKeyExchange Flight)
+            //          --> HS_CLIENT_SUPPLEMENTAL_DATA [optional]
+            //          --> HS_CLIENT_CERTIFICATE or
+            //              HS_CERTIFICATE_URL
+            //          --> HS_CLIENT_KEY_EXCHANGE
+            //          --> HS_CERTIFICATE_VERIFY [optional]
+            //          --> HS_CLIENT_CHANGE_CIPHER_SPEC
+            //          --> HS_CLEINT_FINISHED
+            //              (Server Finished Flight)
+            //          --> HS_CLIENT_SUPPLEMENTAL_DATA [optional]
+            //
+            //          Abbreviated handshake state stacks
+            //              (Server Finished Flight)
+            //              HS_NEW_SESSION_TICKET
+            //          --> HS_SERVER_CHANGE_CIPHER_SPEC
+            //          --> HS_SERVER_FINISHDE
+            //              (Client Finished Flight)
+            //          --> HS_CLIENT_CHANGE_CIPHER_SPEC
+            //          --> HS_CLEINT_FINISHED
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            if (!upcomingStates.isEmpty()) {
+                // The current state should be HS_SERVER_HELLO
+                HandshakeState handshakeState = upcomingStates.pop();
+                HandshakeState alternative = null;
+                if (!alternatives.isEmpty()) {
+                    alternative = alternatives.pop();
+                }
+
+                if ((handshakeState != HS_SERVER_HELLO) &&
+                        (alternative != HS_SERVER_HELLO)) {
+
+                    throw new SSLProtocolException(exceptionMsg);
+                }
+            } else {
+                // No present state.
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // Add the upcoming states.
+            ServerHello serverHello = (ServerHello)handshakeMessage;
+            HelloExtensions hes = serverHello.extensions;
+
+
+            // Not support SessionTicket extension yet.
+            //
+            // boolean hasSessionTicketExt =
+            //     (hes.get(HandshakeMessage.ht_new_session_ticket) != null);
+
+            if (isAbbreviated) {
+                // Not support SessionTicket extension yet.
+                //
+                // // Mandatory NewSessionTicket message
+                // if (hasSessionTicketExt) {
+                //     upcomingStates.add(HS_NEW_SESSION_TICKET);
+                // }
+
+                // Mandatory server ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_SERVER_FINISHDE);
+
+                // Mandatory client ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_CLEINT_FINISHED);
+            } else {
+                // Not support SupplementalData extension yet.
+                //
+                // boolean hasSupplementalDataExt =
+                //     (hes.get(HandshakeMessage.ht_supplemental_data) != null);
+
+                // Not support CertificateStatus extension yet.
+                //
+                // boolean hasCertificateStatusExt =
+                //    (hes.get(HandshakeMessage.ht_certificate_status) != null);
+
+                // Not support CertificateURL extension yet.
+                //
+                // boolean hasCertificateUrlExt =
+                //     (hes.get(HandshakeMessage.ht_certificate_url) != null);
+
+                // Not support SupplementalData extension yet.
+                //
+                // // Optional SupplementalData message
+                // if (hasSupplementalDataExt) {
+                //     upcomingStates.add(HS_SERVER_SUPPLEMENTAL_DATA);
+                // }
+
+                // Need server Certificate message or not?
+                KeyExchange keyExchange = serverHello.cipherSuite.keyExchange;
+                if ((keyExchange != K_KRB5) &&
+                        (keyExchange != K_KRB5_EXPORT) &&
+                        (keyExchange != K_DH_ANON) &&
+                        (keyExchange != K_ECDH_ANON)) {
+                    // Mandatory Certificate message
+                    upcomingStates.add(HS_SERVER_CERTIFICATE);
+                }
+
+                // Not support CertificateStatus extension yet.
+                //
+                // // Optional CertificateStatus message
+                // if (hasCertificateStatusExt) {
+                //     upcomingStates.add(HS_CERTIFICATE_STATUS);
+                // }
+
+                // Need ServerKeyExchange message or not?
+                if ((keyExchange == K_RSA_EXPORT) ||
+                        (keyExchange == K_DHE_RSA) ||
+                        (keyExchange == K_DHE_DSS) ||
+                        (keyExchange == K_DH_ANON) ||
+                        (keyExchange == K_ECDHE_RSA) ||
+                        (keyExchange == K_ECDHE_ECDSA) ||
+                        (keyExchange == K_ECDH_ANON)) {
+                    // Optional ServerKeyExchange message
+                    upcomingStates.add(HS_SERVER_KEY_EXCHANGE);
+                }
+
+                // Optional CertificateRequest message
+                upcomingStates.add(HS_CERTIFICATE_REQUEST);
+
+                // Mandatory ServerHelloDone message
+                upcomingStates.add(HS_SERVER_HELLO_DONE);
+
+                // Not support SupplementalData extension yet.
+                //
+                // // Optional SupplementalData message
+                // if (hasSupplementalDataExt) {
+                //     upcomingStates.add(HS_CLIENT_SUPPLEMENTAL_DATA);
+                // }
+
+                // Optional client Certificate message
+                upcomingStates.add(HS_CLIENT_CERTIFICATE);
+
+                // Not support CertificateURL extension yet.
+                //
+                // // Alternative CertificateURL message, optional too.
+                // //
+                // // Please put CertificateURL rather than Certificate
+                // // message in the alternatives list.  So that we can
+                // // simplify the process of this alternative pair later.
+                // if (hasCertificateUrlExt) {
+                //     alternatives.add(HS_CERTIFICATE_URL);
+                // }
+
+                // Mandatory ClientKeyExchange message
+                upcomingStates.add(HS_CLIENT_KEY_EXCHANGE);
+
+                // Optional CertificateVerify message
+                upcomingStates.add(HS_CERTIFICATE_VERIFY);
+
+                // Mandatory client ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_CLEINT_FINISHED);
+
+                // Not support SessionTicket extension yet.
+                //
+                // // Mandatory NewSessionTicket message
+                // if (hasSessionTicketExt) {
+                //     upcomingStates.add(HS_NEW_SESSION_TICKET);
+                // }
+
+                // Mandatory server ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_SERVER_FINISHDE);
+            }
+
+            break;
+
+        case HandshakeMessage.ht_certificate:
+            //
+            // State machine:
+            //     PRESENT: HS_CERTIFICATE_URL or
+            //              HS_CLIENT_CERTIFICATE
+            //        TO  : HS_CLIENT_KEY_EXCHANGE
+            //
+            //     Or
+            //
+            //     PRESENT: HS_SERVER_CERTIFICATE
+            //        TO  : HS_CERTIFICATE_STATUS [optional]
+            //              HS_SERVER_KEY_EXCHANGE [optional]
+            //              HS_CERTIFICATE_REQUEST [optional]
+            //              HS_SERVER_HELLO_DONE
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            while (!upcomingStates.isEmpty()) {
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState.handshakeType == handshakeType) {
+                    hasPresentState = true;
+
+                    // The current state should be HS_CLIENT_CERTIFICATE or
+                    // HS_SERVER_CERTIFICATE.
+                    //
+                    // Note that we won't put HS_CLIENT_CERTIFICATE into
+                    // the alternative list.
+                    if ((handshakeState != HS_CLIENT_CERTIFICATE) &&
+                            (handshakeState != HS_SERVER_CERTIFICATE)) {
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+
+                    // Is it an expected client Certificate message?
+                    boolean isClientMessage = false;
+                    if (!upcomingStates.isEmpty()) {
+                        // If the next expected message is ClientKeyExchange,
+                        // this one should be an expected client Certificate
+                        // message.
+                        HandshakeState nextState = upcomingStates.getFirst();
+                        if (nextState == HS_CLIENT_KEY_EXCHANGE) {
+                            isClientMessage = true;
+                        }
+                    }
+
+                    if (isClientMessage) {
+                        if (handshakeState != HS_CLIENT_CERTIFICATE) {
+                            throw new SSLProtocolException(exceptionMsg);
+                        }
+
+                        // Not support CertificateURL extension yet.
+                        /*******************************************
+                        // clear up the alternatives list
+                        if (!alternatives.isEmpty()) {
+                            HandshakeState alternative = alternatives.pop();
+
+                            if (alternative != HS_CERTIFICATE_URL) {
+                                throw new SSLProtocolException(exceptionMsg);
+                            }
+                        }
+                        ********************************************/
+                    } else {
+                        if ((handshakeState != HS_SERVER_CERTIFICATE)) {
+                            throw new SSLProtocolException(exceptionMsg);
+                        }
+                    }
+
+                    break;
+                } else if (!handshakeState.isOptional) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }   // Otherwise, looking for next state track.
+            }
+
+            // No present state.
+            if (!hasPresentState) {
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // no new upcoming states.
+
+            break;
+
+        // Not support CertificateURL extension yet.
+        /*************************************************/
+        case HandshakeMessage.ht_certificate_url:
+            //
+            // State machine:
+            //     PRESENT: HS_CERTIFICATE_URL or
+            //              HS_CLIENT_CERTIFICATE
+            //        TO  : HS_CLIENT_KEY_EXCHANGE
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            while (!upcomingStates.isEmpty()) {
+                // The current state should be HS_CLIENT_CERTIFICATE.
+                //
+                // Note that we won't put HS_CLIENT_CERTIFICATE into
+                // the alternative list.
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState.handshakeType ==
+                        HS_CLIENT_CERTIFICATE.handshakeType) {
+                    hasPresentState = true;
+
+                    // Look for HS_CERTIFICATE_URL state track.
+                    if (!alternatives.isEmpty()) {
+                        HandshakeState alternative = alternatives.pop();
+
+                        if (alternative != HS_CERTIFICATE_URL) {
+                            throw new SSLProtocolException(exceptionMsg);
+                        }
+                    } else {
+                        // No alternative CertificateUR state track.
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+
+                    if ((handshakeState != HS_CLIENT_CERTIFICATE)) {
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+
+                    break;
+                } else if (!handshakeState.isOptional) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }   // Otherwise, looking for next state track.
+
+            }
+
+            // No present state.
+            if (!hasPresentState) {
+                // No present state.
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // no new upcoming states.
+
+            break;
+        /*************************************************/
+
+        default:
+            // Check and update the present state.
+            while (!upcomingStates.isEmpty()) {
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState.handshakeType == handshakeType) {
+                    hasPresentState = true;
+                    break;
+                } else if (!handshakeState.isOptional) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }   // Otherwise, looking for next state track.
+            }
+
+            // No present state.
+            if (!hasPresentState) {
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // no new upcoming states.
+        }
+
+        if (debugIsOn) {
+            for (HandshakeState handshakeState : upcomingStates) {
+                System.out.println(
+                    "upcoming handshake states: " + handshakeState);
+            }
+            for (HandshakeState handshakeState : alternatives) {
+                System.out.println(
+                    "upcoming handshake alternative state: " + handshakeState);
+            }
+        }
+    }
+
+    void changeCipherSpec(boolean isInput,
+            boolean isClient) throws SSLProtocolException {
+
+        if (debugIsOn) {
+            System.out.println(
+                    "update handshake state: change_cipher_spec");
+        }
+
+        String exceptionMsg = "ChangeCipherSpec message sequence violation";
+
+        HandshakeState expectedState;
+        if ((isClient && isInput) || (!isClient && !isInput)) {
+            expectedState = HS_SERVER_CHANGE_CIPHER_SPEC;
+        } else {
+            expectedState = HS_CLIENT_CHANGE_CIPHER_SPEC;
+        }
+
+        boolean hasPresentState = false;
+
+        // Check and update the present state.
+        while (!upcomingStates.isEmpty()) {
+            HandshakeState handshakeState = upcomingStates.pop();
+            if (handshakeState == expectedState) {
+                hasPresentState = true;
+                break;
+            } else if (!handshakeState.isOptional) {
+                throw new SSLProtocolException(exceptionMsg);
+            }   // Otherwise, looking for next state track.
+        }
+
+        // No present state.
+        if (!hasPresentState) {
+            throw new SSLProtocolException(exceptionMsg);
+        }
+
+        // no new upcoming states.
+
+        if (debugIsOn) {
+            for (HandshakeState handshakeState : upcomingStates) {
+                System.out.println(
+                    "upcoming handshake states: " + handshakeState);
+            }
+            for (HandshakeState handshakeState : alternatives) {
+                System.out.println(
+                    "upcoming handshake alternative state: " + handshakeState);
+            }
+        }
+    }
+
+    private static String toString(byte handshakeType) {
+        String s = handshakeTypes.get(handshakeType);
+        if (s == null) {
+            s = "unknown";
+        }
+        return (s + "[" + handshakeType + "]");
+    }
+}
+
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Mon Jun 01 10:29:06 2015 -0400
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Tue Jun 02 04:01:04 2015 +0000
@@ -29,6 +29,7 @@
 import java.io.*;
 import java.util.*;
 import java.security.*;
+import java.nio.ByteBuffer;
 import java.security.NoSuchAlgorithmException;
 import java.security.AccessController;
 import java.security.AlgorithmConstraints;
@@ -83,7 +84,7 @@
     private CipherSuiteList     enabledCipherSuites;
 
     // The endpoint identification protocol
-    String              identificationProtocol;
+    String                      identificationProtocol;
 
     // The cryptographic algorithm constraints
     private AlgorithmConstraints    algorithmConstraints = null;
@@ -109,12 +110,15 @@
      * Active cipher suites is a subset of enabled cipher suites, and will
      * contain only those cipher suites available for the active protocols.
      */
-    private CipherSuiteList    activeCipherSuites;
+    private CipherSuiteList     activeCipherSuites;
 
     // The server name indication and matchers
     List<SNIServerName> serverNames = Collections.<SNIServerName>emptyList();
     Collection<SNIMatcher> sniMatchers = Collections.<SNIMatcher>emptyList();
 
+    // The maximum expected network packet size for SSL/TLS/DTLS records.
+    int                         maximumPacketSize = 0;
+
     private boolean             isClient;
     private boolean             needCertVerify;
 
@@ -124,11 +128,16 @@
     HandshakeHash               handshakeHash;
     HandshakeInStream           input;
     HandshakeOutStream          output;
-    int                         state;
     SSLContextImpl              sslContext;
     RandomCookie                clnt_random, svr_random;
     SSLSessionImpl              session;
 
+    HandshakeStateManager       handshakeState;
+    boolean                     clientHelloDelivered;
+    boolean                     serverHelloRequested;
+    boolean                     handshakeActivated;
+    boolean                     handshakeFinished;
+
     // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
     CipherSuite         cipherSuite;
 
@@ -141,10 +150,6 @@
     // True if it's OK to start a new SSL session
     boolean             enableNewSession;
 
-    // True if session keys have been calculated and the caller may receive
-    // and process a ChangeCipherSpec message
-    private boolean sessKeysCalculated;
-
     // Whether local cipher suites preference should be honored during
     // handshaking?
     //
@@ -207,12 +212,18 @@
     // need to dispose the object when it is invalidated
     boolean invalidated;
 
+    /*
+     * Is this an instance for Datagram Transport Layer Security (DTLS)?
+     */
+    final boolean isDTLS;
+
     Handshaker(SSLSocketImpl c, SSLContextImpl context,
             ProtocolList enabledProtocols, boolean needCertVerify,
             boolean isClient, ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
             byte[] clientVerifyData, byte[] serverVerifyData) {
         this.conn = c;
+        this.isDTLS = false;
         init(context, enabledProtocols, needCertVerify, isClient,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
             clientVerifyData, serverVerifyData);
@@ -222,8 +233,10 @@
             ProtocolList enabledProtocols, boolean needCertVerify,
             boolean isClient, ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
-            byte[] clientVerifyData, byte[] serverVerifyData) {
+            byte[] clientVerifyData, byte[] serverVerifyData,
+            boolean isDTLS) {
         this.engine = engine;
+        this.isDTLS = isDTLS;
         init(context, enabledProtocols, needCertVerify, isClient,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
             clientVerifyData, serverVerifyData);
@@ -251,9 +264,13 @@
         this.secureRenegotiation = secureRenegotiation;
         this.clientVerifyData = clientVerifyData;
         this.serverVerifyData = serverVerifyData;
-        enableNewSession = true;
-        invalidated = false;
-        sessKeysCalculated = false;
+        this.enableNewSession = true;
+        this.invalidated = false;
+        this.handshakeState = new HandshakeStateManager(isDTLS);
+        this.clientHelloDelivered = false;
+        this.serverHelloRequested = false;
+        this.handshakeActivated = false;
+        this.handshakeFinished = false;
 
         setCipherSuite(CipherSuite.C_NULL);
         setEnabledProtocols(enabledProtocols);
@@ -263,22 +280,6 @@
         } else {        // engine != null
             algorithmConstraints = new SSLAlgorithmConstraints(engine, true);
         }
-
-
-        //
-        // In addition to the connection state machine, controlling
-        // how the connection deals with the different sorts of records
-        // that get sent (notably handshake transitions!), there's
-        // also a handshaking state machine that controls message
-        // sequencing.
-        //
-        // It's a convenient artifact of the protocol that this can,
-        // with only a couple of minor exceptions, be driven by the
-        // type constant for the last message seen:  except for the
-        // client's cert verify, those constants are in a convenient
-        // order to drastically simplify state machine checking.
-        //
-        state = -2;  // initialized but not activated
     }
 
     /*
@@ -360,14 +361,6 @@
         }
     }
 
-    final boolean receivedChangeCipherSpec() {
-        if (conn != null) {
-            return conn.receivedChangeCipherSpec();
-        } else {
-            return engine.receivedChangeCipherSpec();
-        }
-    }
-
     String getEndpointIdentificationAlgorithmSE() {
         SSLParameters paras;
         if (conn != null) {
@@ -395,8 +388,6 @@
     void setVersion(ProtocolVersion protocolVersion) {
         this.protocolVersion = protocolVersion;
         setVersionSE(protocolVersion);
-
-        output.r.setVersion(protocolVersion);
     }
 
     /**
@@ -483,6 +474,13 @@
     }
 
     /**
+     * Sets the maximum packet size of the handshaking.
+     */
+    void setMaximumPacketSize(int maximumPacketSize) {
+        this.maximumPacketSize = maximumPacketSize;
+    }
+
+    /**
      * Sets the cipher suites preference.
      */
     void setUseCipherSuitesOrder(boolean on) {
@@ -532,23 +530,29 @@
         handshakeHash = new HandshakeHash(needCertVerify);
 
         // Generate handshake input/output stream.
-        input = new HandshakeInStream(handshakeHash);
         if (conn != null) {
-            output = new HandshakeOutStream(protocolVersion, helloVersion,
-                                        handshakeHash, conn);
-            conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
-            conn.getAppInputStream().r.setHelloVersion(helloVersion);
-            conn.getAppOutputStream().r.setHelloVersion(helloVersion);
-        } else {
-            output = new HandshakeOutStream(protocolVersion, helloVersion,
-                                        handshakeHash, engine);
+            input = new HandshakeInStream();
+            output = new HandshakeOutStream(conn.outputRecord);
+
+            conn.inputRecord.setHandshakeHash(handshakeHash);
+            conn.inputRecord.setHelloVersion(helloVersion);
+
+            conn.outputRecord.setHandshakeHash(handshakeHash);
+            conn.outputRecord.setHelloVersion(helloVersion);
+            conn.outputRecord.setVersion(protocolVersion);
+        } else if (engine != null) {
+            input = new HandshakeInStream();
+            output = new HandshakeOutStream(engine.outputRecord);
+
             engine.inputRecord.setHandshakeHash(handshakeHash);
             engine.inputRecord.setHelloVersion(helloVersion);
+
+            engine.outputRecord.setHandshakeHash(handshakeHash);
             engine.outputRecord.setHelloVersion(helloVersion);
+            engine.outputRecord.setVersion(protocolVersion);
         }
 
-        // move state to activated
-        state = -1;
+        handshakeActivated = true;
     }
 
     /**
@@ -637,15 +641,15 @@
             if (!(activeProtocols.collection().isEmpty()) &&
                     activeProtocols.min.v != ProtocolVersion.NONE.v) {
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (suite.obsoleted > activeProtocols.min.v &&
-                            suite.supported <= activeProtocols.max.v) {
+                    if (!activeProtocols.min.obsoletes(suite) &&
+                            activeProtocols.max.supports(suite)) {
                         if (algorithmConstraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 suite.name, null)) {
                             suites.add(suite);
                         }
                     } else if (debug != null && Debug.isOn("verbose")) {
-                        if (suite.obsoleted <= activeProtocols.min.v) {
+                        if (activeProtocols.min.obsoletes(suite)) {
                             System.out.println(
                                 "Ignoring obsoleted cipher suite: " + suite);
                         } else {
@@ -700,8 +704,8 @@
 
                 boolean found = false;
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (suite.isAvailable() && suite.obsoleted > protocol.v &&
-                                               suite.supported <= protocol.v) {
+                    if (suite.isAvailable() && (!protocol.obsoletes(suite)) &&
+                                               protocol.supports(suite)) {
                         if (algorithmConstraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 suite.name, null)) {
@@ -837,7 +841,7 @@
      * this freshly created session can become the current one.
      */
     boolean isDone() {
-        return state == HandshakeMessage.ht_finished;
+        return started() && handshakeState.isEmpty() && handshakeFinished;
     }
 
 
@@ -861,6 +865,14 @@
         }
     }
 
+    void expectingFinishFlightSE() {
+        if (conn != null) {
+            conn.expectingFinishFlight();
+        } else {
+            engine.expectingFinishFlight();
+        }
+    }
+
     /*
      * Returns true if renegotiation is in use for this connection.
      */
@@ -886,8 +898,8 @@
      * This routine is fed SSL handshake records when they become available,
      * and processes messages found therein.
      */
-    void process_record(InputRecord r, boolean expectingFinished)
-            throws IOException {
+    void processRecord(ByteBuffer record,
+            boolean expectingFinished) throws IOException {
 
         checkThrown();
 
@@ -895,7 +907,7 @@
          * Store the incoming handshake data, then see if we can
          * now process any completed handshake messages
          */
-        input.incomingRecord(r);
+        input.incomingRecord(record);
 
         /*
          * We don't need to create a separate delegatable task
@@ -946,6 +958,13 @@
                 return;
             }
 
+            // Set the flags in the message receiving side.
+            if (messageType == HandshakeMessage.ht_client_hello) {
+                clientHelloDelivered = true;
+            } else if (messageType == HandshakeMessage.ht_hello_request) {
+                serverHelloRequested = true;
+            }
+
             /*
              * Process the message.  We require
              * that processMessage() consumes the entire message.  In
@@ -961,14 +980,16 @@
              * Also, note that hello request messages are never hashed;
              * that includes the hello request header, too.
              */
-            if (messageType == HandshakeMessage.ht_hello_request) {
-                input.reset();
-                processMessage(messageType, messageLen);
-                input.ignore(4 + messageLen);
-            } else {
-                input.mark(messageLen);
-                processMessage(messageType, messageLen);
-                input.digestNow();
+            processMessage(messageType, messageLen);
+
+            // Reload if this message has been reserved.
+            //
+            // Note: in the implementation, only certificate_verify and
+            // finished messages are reserved.
+            if ((messageType == HandshakeMessage.ht_finished) ||
+                (messageType == HandshakeMessage.ht_certificate_verify)) {
+
+                handshakeHash.reload();
             }
         }
     }
@@ -980,29 +1001,29 @@
      * In activated state, the handshaker may not send any messages out.
      */
     boolean activated() {
-        return state >= -1;
+        return handshakeActivated;
     }
 
     /**
      * Returns true iff the handshaker has sent any messages.
      */
     boolean started() {
-        return state >= 0;  // 0: HandshakeMessage.ht_hello_request
-                            // 1: HandshakeMessage.ht_client_hello
+        return (serverHelloRequested || clientHelloDelivered);
     }
 
-
     /*
      * Used to kickstart the negotiation ... either writing a
      * ClientHello or a HelloRequest as appropriate, whichever
      * the subclass returns.  NOP if handshaking's already started.
      */
     void kickstart() throws IOException {
-        if (state >= 0) {
+        if ((isClient && clientHelloDelivered) ||
+                (!isClient && serverHelloRequested)) {
             return;
         }
 
         HandshakeMessage m = getKickstartMessage();
+        handshakeState.update(m, resumingSession);
 
         if (debug != null && Debug.isOn("handshake")) {
             m.print(System.out);
@@ -1010,7 +1031,13 @@
         m.write(output);
         output.flush();
 
-        state = m.messageType();
+        // Set the flags in the message delivering side.
+        int handshakeType = m.messageType();
+        if (handshakeType == HandshakeMessage.ht_hello_request) {
+            serverHelloRequested = true;
+        } else {        // HandshakeMessage.ht_client_hello
+            clientHelloDelivered = true;
+        }
     }
 
     /**
@@ -1052,24 +1079,16 @@
          * We already hold SSLEngine/SSLSocket "this" by virtue
          * of this being called from the readRecord code.
          */
-        OutputRecord r;
-        if (conn != null) {
-            r = new OutputRecord(Record.ct_change_cipher_spec);
-        } else {
-            r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine);
-        }
-
-        r.setVersion(protocolVersion);
-        r.write(1);     // single byte of data
-
         if (conn != null) {
             conn.writeLock.lock();
             try {
-                conn.writeRecord(r);
+                handshakeState.changeCipherSpec(false, isClient);
                 conn.changeWriteCiphers();
                 if (debug != null && Debug.isOn("handshake")) {
                     mesg.print(System.out);
                 }
+
+                handshakeState.update(mesg, resumingSession);
                 mesg.write(output);
                 output.flush();
             } finally {
@@ -1077,19 +1096,25 @@
             }
         } else {
             synchronized (engine.writeLock) {
-                engine.writeRecord((EngineOutputRecord)r);
+                handshakeState.changeCipherSpec(false, isClient);
                 engine.changeWriteCiphers();
                 if (debug != null && Debug.isOn("handshake")) {
                     mesg.print(System.out);
                 }
+
+                handshakeState.update(mesg, resumingSession);
                 mesg.write(output);
-
-                if (lastMessage) {
-                    output.setFinishedMsg();
-                }
                 output.flush();
             }
         }
+
+        if (lastMessage) {
+            handshakeFinished = true;
+        }
+    }
+
+    void receiveChangeCipherSpec() throws IOException {
+        handshakeState.changeCipherSpec(true, isClient);
     }
 
     /*
@@ -1131,12 +1156,31 @@
         String masterAlg;
         PRF prf;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
-            masterAlg = "SunTls12MasterSecret";
-            prf = cipherSuite.prfAlg;
+        byte majorVersion = protocolVersion.major;
+        byte minorVersion = protocolVersion.minor;
+        if (protocolVersion.isDTLSProtocol()) {
+            // Use TLS version number for DTLS key calculation
+            if (protocolVersion.v == ProtocolVersion.DTLS10.v) {
+                majorVersion = ProtocolVersion.TLS11.major;
+                minorVersion = ProtocolVersion.TLS11.minor;
+
+                masterAlg = "SunTlsMasterSecret";
+                prf = P_NONE;
+            } else {    // DTLS 1.2
+                majorVersion = ProtocolVersion.TLS12.major;
+                minorVersion = ProtocolVersion.TLS12.minor;
+
+                masterAlg = "SunTls12MasterSecret";
+                prf = cipherSuite.prfAlg;
+            }
         } else {
-            masterAlg = "SunTlsMasterSecret";
-            prf = P_NONE;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                masterAlg = "SunTls12MasterSecret";
+                prf = cipherSuite.prfAlg;
+            } else {
+                masterAlg = "SunTlsMasterSecret";
+                prf = P_NONE;
+            }
         }
 
         String prfHashAlg = prf.getPRFHashAlg();
@@ -1145,7 +1189,7 @@
 
         @SuppressWarnings("deprecation")
         TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec(
-                preMasterSecret, protocolVersion.major, protocolVersion.minor,
+                preMasterSecret, (majorVersion & 0xFF), (minorVersion & 0xFF),
                 clnt_random.random_bytes, svr_random.random_bytes,
                 prfHashAlg, prfHashLength, prfBlockSize);
 
@@ -1196,36 +1240,55 @@
         String keyMaterialAlg;
         PRF prf;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
-            keyMaterialAlg = "SunTls12KeyMaterial";
-            prf = cipherSuite.prfAlg;
+        byte majorVersion = protocolVersion.major;
+        byte minorVersion = protocolVersion.minor;
+        if (protocolVersion.isDTLSProtocol()) {
+            // Use TLS version number for DTLS key calculation
+            if (protocolVersion.v == ProtocolVersion.DTLS10.v) {
+                majorVersion = ProtocolVersion.TLS11.major;
+                minorVersion = ProtocolVersion.TLS11.minor;
+
+                keyMaterialAlg = "SunTlsKeyMaterial";
+                prf = P_NONE;
+            } else {    // DTLS 1.2+
+                majorVersion = ProtocolVersion.TLS12.major;
+                minorVersion = ProtocolVersion.TLS12.minor;
+
+                keyMaterialAlg = "SunTls12KeyMaterial";
+                prf = cipherSuite.prfAlg;
+            }
         } else {
-            keyMaterialAlg = "SunTlsKeyMaterial";
-            prf = P_NONE;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                keyMaterialAlg = "SunTls12KeyMaterial";
+                prf = cipherSuite.prfAlg;
+            } else {
+                keyMaterialAlg = "SunTlsKeyMaterial";
+                prf = P_NONE;
+            }
         }
 
         String prfHashAlg = prf.getPRFHashAlg();
         int prfHashLength = prf.getPRFHashLength();
         int prfBlockSize = prf.getPRFBlockSize();
 
-        // TLS v1.1 or later uses an explicit IV in CBC cipher suites to
+        // TLS v1.1+ and DTLS use an explicit IV in CBC cipher suites to
         // protect against the CBC attacks.  AEAD/GCM cipher suites in TLS
         // v1.2 or later use a fixed IV as the implicit part of the partially
         // implicit nonce technique described in RFC 5116.
         int ivSize = cipher.ivSize;
         if (cipher.cipherType == AEAD_CIPHER) {
             ivSize = cipher.fixedIvSize;
-        } else if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
-                cipher.cipherType == BLOCK_CIPHER) {
+        } else if ((cipher.cipherType == BLOCK_CIPHER) &&
+                protocolVersion.useTLS11PlusSpec()) {
             ivSize = 0;
         }
 
         TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
-            masterKey, protocolVersion.major, protocolVersion.minor,
-            clnt_random.random_bytes, svr_random.random_bytes,
-            cipher.algorithm, cipher.keySize, expandedKeySize,
-            ivSize, hashSize,
-            prfHashAlg, prfHashLength, prfBlockSize);
+                masterKey, (majorVersion & 0xFF), (minorVersion & 0xFF),
+                clnt_random.random_bytes, svr_random.random_bytes,
+                cipher.algorithm, cipher.keySize, expandedKeySize,
+                ivSize, hashSize,
+                prfHashAlg, prfHashLength, prfBlockSize);
 
         try {
             KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg);
@@ -1247,10 +1310,6 @@
             throw new ProviderException(e);
         }
 
-        // Mark a flag that allows outside entities (like SSLSocket/SSLEngine)
-        // determine if a ChangeCipherSpec message could be processed.
-        sessKeysCalculated = true;
-
         //
         // Dump the connection keys as they're generated.
         //
@@ -1293,7 +1352,7 @@
                     System.out.println("Server write IV:");
                     printHex(dump, svrWriteIV.getIV());
                 } else {
-                    if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    if (protocolVersion.useTLS11PlusSpec()) {
                         System.out.println(
                                 "... no IV derived for this protocol");
                     } else {
@@ -1305,15 +1364,6 @@
         }
     }
 
-    /**
-     * Return whether or not the Handshaker has derived session keys for
-     * this handshake.  This is used for determining readiness to process
-     * an incoming ChangeCipherSpec message.
-     */
-    boolean sessionKeysCalculated() {
-        return sessKeysCalculated;
-    }
-
     private static void printHex(HexDumpEncoder dump, byte[] bytes) {
         if (bytes == null) {
             System.out.println("(key bytes not available)");
@@ -1326,19 +1376,6 @@
         }
     }
 
-    /**
-     * Throw an SSLException with the specified message and cause.
-     * Shorthand until a new SSLException constructor is added.
-     * This method never returns.
-     */
-    static void throwSSLException(String msg, Throwable cause)
-            throws SSLException {
-        SSLException e = new SSLException(msg);
-        e.initCause(cause);
-        throw e;
-    }
-
-
     /*
      * Implement a simple task delegator.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java	Tue Jun 02 04:01:04 2015 +0000
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import javax.net.ssl.SSLProtocolException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+
+import sun.security.ssl.HandshakeMessage.ClientHello;
+
+/*
+ * HelloVerifyRequest cookie manager
+ */
+final class HelloCookieManager {
+    // the cookie secret life time
+    private static long COOKIE_TIMING_WINDOW = 3600000;     // in milliseconds
+    private static int  COOKIE_MAX_LENGTH_DTLS10 = 32;      // 32 bytes
+    private static int  COOKIE_MAX_LENGTH_DTLS12 = 0xFF;    // 2^8 -1 bytes
+
+    private final SecureRandom          secureRandom;
+    private final MessageDigest         cookieDigest;
+
+    private int                         cookieVersion;      // allow to wrap
+    private long                        secretLifetime;
+    private byte[]                      cookieSecret;
+
+    private int                         prevCookieVersion;
+    private byte[]                      prevCookieSecret;
+
+    HelloCookieManager(SecureRandom secureRandom) {
+        this.secureRandom = secureRandom;
+        this.cookieDigest = JsseJce.getMessageDigest("SHA-256");
+
+        this.cookieVersion = secureRandom.nextInt();
+        this.secretLifetime = 0;
+        this.cookieSecret = null;
+
+        this.prevCookieVersion = 0;
+        this.prevCookieSecret = null;
+    }
+
+    // Used by server side to generate cookies in HelloVerifyRequest message.
+    synchronized byte[] getCookie(ClientHello clientHelloMsg) {
+        if (secretLifetime < System.currentTimeMillis()) {
+            if (cookieSecret != null) {
+                prevCookieVersion = cookieVersion;
+                prevCookieSecret = cookieSecret.clone();
+            } else {
+                cookieSecret = new byte[32];
+            }
+
+            cookieVersion++;
+            secureRandom.nextBytes(cookieSecret);
+            secretLifetime = System.currentTimeMillis() + COOKIE_TIMING_WINDOW;
+        }
+
+        clientHelloMsg.updateHelloCookie(cookieDigest);
+        byte[] cookie = cookieDigest.digest(cookieSecret);      // 32 bytes
+        cookie[0] = (byte)((cookieVersion >> 24) & 0xFF);
+        cookie[1] = (b