changeset 14145:a39036fa30bb

8245681: Add TLSv1.3 regression test from 11.0.7 Reviewed-by: mbalao
author abakhtin
date Tue, 25 Aug 2020 18:12:01 +0300
parents 6c6e8ab540a1
children e329505b1e6a
files test/java/security/testlibrary/CertificateBuilder.java test/java/security/testlibrary/SimpleOCSPServer.java test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java test/javax/net/ssl/FixingJavadocs/ComURLNulls.java test/javax/net/ssl/FixingJavadocs/SSLSessionNulls.java test/javax/net/ssl/SSLEngine/Arrays.java test/javax/net/ssl/SSLEngine/CheckStatus.java test/javax/net/ssl/SSLEngine/ConnectionTest.java test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java test/javax/net/ssl/SSLEngine/ExtendedKeyEngine.java test/javax/net/ssl/SSLEngine/IllegalHandshakeMessage.java test/javax/net/ssl/SSLEngine/IllegalRecordVersion.java test/javax/net/ssl/SSLEngine/LargeBufs.java test/javax/net/ssl/SSLEngine/NoAuthClientAuth.java test/javax/net/ssl/SSLSession/RenegotiateTLS13.java test/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java test/javax/net/ssl/SSLSession/SessionTimeOutTests.java test/javax/net/ssl/SSLSession/TestEnabledProtocols.java test/javax/net/ssl/SSLSocket/InputStreamClosure.java test/javax/net/ssl/SSLSocket/OutputStreamClosure.java test/javax/net/ssl/SSLSocket/Tls13PacketSize.java test/javax/net/ssl/ServerName/SSLSocketExplorerFailure.java test/javax/net/ssl/ServerName/SSLSocketSNISensitive.java test/javax/net/ssl/Stapling/HttpsUrlConnClient.java test/javax/net/ssl/Stapling/SSLEngineWithStapling.java test/javax/net/ssl/Stapling/SSLSocketWithStapling.java test/javax/net/ssl/Stapling/StapleEnableProps.java test/javax/net/ssl/TLS/CipherTestUtils.java test/javax/net/ssl/TLS/JSSEClient.java test/javax/net/ssl/TLS/JSSEServer.java test/javax/net/ssl/TLS/TLSClientPropertyTest.java test/javax/net/ssl/TLS/TLSDataExchangeTest.java test/javax/net/ssl/TLS/TLSEnginesClosureTest.java test/javax/net/ssl/TLS/TLSHandshakeTest.java test/javax/net/ssl/TLS/TLSMFLNTest.java test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java test/javax/net/ssl/TLS/TLSRehandshakeTest.java test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java test/javax/net/ssl/TLS/TestJSSE.java test/javax/net/ssl/TLS/TestJSSEClientDefaultProtocol.java test/javax/net/ssl/TLS/TestJSSEClientProtocol.java test/javax/net/ssl/TLS/TestJSSENoCommonProtocols.java test/javax/net/ssl/TLS/TestJSSEServerProtocol.java test/javax/net/ssl/TLSCommon/BufferOverflowUnderflowTest.java test/javax/net/ssl/TLSCommon/CipherSuite.java test/javax/net/ssl/TLSCommon/ConcurrentClientAccessTest.java test/javax/net/ssl/TLSCommon/DataExchangeTest.java test/javax/net/ssl/TLSCommon/EnginesClosureTest.java test/javax/net/ssl/TLSCommon/HandshakeTest.java test/javax/net/ssl/TLSCommon/KeyAlgorithm.java test/javax/net/ssl/TLSCommon/KeyExAlgorithm.java test/javax/net/ssl/TLSCommon/MFLNTest.java test/javax/net/ssl/TLSCommon/NotEnabledRC4Test.java test/javax/net/ssl/TLSCommon/Protocol.java test/javax/net/ssl/TLSCommon/RehandshakeTest.java test/javax/net/ssl/TLSCommon/RehandshakeWithCipherChangeTest.java test/javax/net/ssl/TLSCommon/RehandshakeWithDataExTest.java test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java test/javax/net/ssl/TLSCommon/TLSTest.java test/javax/net/ssl/TLSCommon/TestSessionLocalPrincipal.java test/javax/net/ssl/TLSCommon/UnsupportedCiphersTest.java test/javax/net/ssl/TLSCommon/jaas.conf test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java test/javax/net/ssl/TLSv1/TLSHandshakeTest.java test/javax/net/ssl/TLSv1/TLSMFLNTest.java test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java test/javax/net/ssl/TLSv11/ExportableBlockCipher.java test/javax/net/ssl/TLSv11/ExportableStreamCipher.java test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java test/javax/net/ssl/TLSv11/TLSHandshakeTest.java test/javax/net/ssl/TLSv11/TLSMFLNTest.java test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java test/javax/net/ssl/TLSv12/DisabledShortDSAKeys.java test/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java test/javax/net/ssl/TLSv12/ShortRSAKey512.java test/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java test/javax/net/ssl/TLSv12/SignatureAlgorithms.java test/javax/net/ssl/TLSv12/TLSEnginesClosureTest.java test/javax/net/ssl/ciphersuites/DisabledAlgorithms.java test/javax/net/ssl/ciphersuites/ECCurvesconstraints.java test/javax/net/ssl/compatibility/Cert.java test/javax/net/ssl/compatibility/Client.java test/javax/net/ssl/compatibility/ClientHelloProcessing.java test/javax/net/ssl/compatibility/Compatibility.java test/javax/net/ssl/compatibility/JdkInfo.java test/javax/net/ssl/compatibility/JdkRelease.java test/javax/net/ssl/compatibility/JdkUtils.java test/javax/net/ssl/compatibility/ProcessUtils.java test/javax/net/ssl/compatibility/README test/javax/net/ssl/compatibility/Server.java test/javax/net/ssl/compatibility/Status.java test/javax/net/ssl/compatibility/TestCase.java test/javax/net/ssl/compatibility/UseCase.java test/javax/net/ssl/compatibility/Utils.java test/javax/net/ssl/compatibility/java.security test/javax/net/ssl/etc/README test/javax/net/ssl/etc/keystore test/javax/net/ssl/etc/truststore test/javax/net/ssl/interop/ClientHelloBufferUnderflowException.java test/javax/net/ssl/interop/ClientHelloChromeInterOp.java test/javax/net/ssl/interop/ClientHelloInterOp.java test/javax/net/ssl/sanity/CacertsExplorer.java test/javax/net/ssl/sanity/ciphersuites/CheckCipherSuites.java test/javax/net/ssl/sanity/ciphersuites/CipherSuitesInOrder.java test/javax/net/ssl/sanity/interop/CipherTest.java test/javax/net/ssl/sanity/interop/ClientJSSEServerJSSE.java test/javax/net/ssl/sanity/interop/JSSEClient.java test/javax/net/ssl/sanity/interop/JSSEServer.java test/javax/net/ssl/templates/SSLContextTemplate.java test/javax/net/ssl/templates/SSLEngineTemplate.java test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java test/javax/net/ssl/templates/SSLSocketTemplate.java test/sun/net/www/protocol/https/HttpsClient/ProxyAuthTest.java test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java test/sun/net/www/protocol/https/HttpsURLConnection/B6216082.java test/sun/net/www/protocol/https/HttpsURLConnection/ReadTimeout.java test/sun/net/www/protocol/https/NewImpl/ComHTTPSConnection.java test/sun/net/www/protocol/https/NewImpl/ComHostnameVerifier.java test/sun/security/pkcs11/sslecc/CipherTest.java test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java test/sun/security/pkcs11/sslecc/JSSEClient.java test/sun/security/pkcs11/sslecc/JSSEServer.java test/sun/security/pkcs11/sslecc/policy test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java test/sun/security/provider/certpath/ResponderId/ResponderIdTests.java test/sun/security/ssl/AppInputStream/ReadBlocksClose.java test/sun/security/ssl/AppInputStream/ReadHandshake.java test/sun/security/ssl/AppOutputStream/NoExceptionOnClose.java test/sun/security/ssl/CertPathRestrictions/JSSEServer.java test/sun/security/ssl/CertPathRestrictions/TLSRestrictions.java test/sun/security/ssl/CipherSuite/SSL_NULL.java test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java test/sun/security/ssl/DHKeyExchange/LegacyDHEKeyExchange.java test/sun/security/ssl/DHKeyExchange/UseStrongDHSizes.java test/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.sh test/sun/security/ssl/GenSSLConfigs/main.java test/sun/security/ssl/InputRecord/SSLSocketTimeoutNulls.java test/sun/security/ssl/SSLContextImpl/CustomizedDefaultProtocols.java test/sun/security/ssl/SSLContextImpl/CustomizedServerDefaultProtocols.java test/sun/security/ssl/SSLContextImpl/DefaultEnabledProtocols.java test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java test/sun/security/ssl/SSLContextImpl/NoOldVersionContext.java test/sun/security/ssl/SSLContextImpl/TrustTrustedCert.java test/sun/security/ssl/SSLEngineImpl/CloseEngineException.java test/sun/security/ssl/SSLEngineImpl/CloseStart.java test/sun/security/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java test/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java test/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java test/sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java test/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java test/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java test/sun/security/ssl/SSLEngineImpl/TLS13BeginHandshake.java test/sun/security/ssl/SSLSessionImpl/ResumeChecksClient.java test/sun/security/ssl/SSLSessionImpl/ResumeChecksServer.java test/sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java test/sun/security/ssl/SSLSocketImpl/CheckMethods.java test/sun/security/ssl/SSLSocketImpl/ClientTimeout.java test/sun/security/ssl/SSLSocketImpl/InvalidateServerSessionRenegotiate.java test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java test/sun/security/ssl/SSLSocketImpl/NoImpactServerRenego.java test/sun/security/ssl/SSLSocketImpl/NonAutoClose.java test/sun/security/ssl/SSLSocketImpl/RejectClientRenego.java test/sun/security/ssl/SSLSocketImpl/SSLExceptionForIOIssue.java test/sun/security/ssl/SSLSocketImpl/SSLSocketImplThrowsWrongExceptions.java test/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java test/sun/security/ssl/SSLSocketImpl/ServerRenegoWithTwoVersions.java test/sun/security/ssl/SSLSocketImpl/SetClientMode.java test/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java test/sun/security/ssl/SignatureScheme/Tls13NamedGroups.java test/sun/security/ssl/SocketCreation/SocketCreation.java test/sun/security/ssl/Stapling/StatusResponseManager.java test/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java test/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java test/sun/security/ssl/X509TrustManagerImpl/CertRequestOverflow.java test/sun/security/ssl/X509TrustManagerImpl/ClientServer.java test/sun/security/ssl/X509TrustManagerImpl/SelfIssuedCert.java test/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java test/sun/security/ssl/internal/TestRun.java test/sun/security/ssl/internal/java.base/sun/security/ssl/TestHkdf.java
diffstat 193 files changed, 51827 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/testlibrary/CertificateBuilder.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,539 @@
+/*
+ * 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.testlibrary;
+
+import java.io.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.Extension;
+import javax.security.auth.x500.X500Principal;
+import java.math.BigInteger;
+
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AccessDescription;
+import sun.security.x509.AlgorithmId;
+import sun.security.x509.AuthorityInfoAccessExtension;
+import sun.security.x509.AuthorityKeyIdentifierExtension;
+import sun.security.x509.SubjectKeyIdentifierExtension;
+import sun.security.x509.BasicConstraintsExtension;
+import sun.security.x509.ExtendedKeyUsageExtension;
+import sun.security.x509.DNSName;
+import sun.security.x509.GeneralName;
+import sun.security.x509.GeneralNames;
+import sun.security.x509.KeyUsageExtension;
+import sun.security.x509.SerialNumber;
+import sun.security.x509.SubjectAlternativeNameExtension;
+import sun.security.x509.URIName;
+import sun.security.x509.KeyIdentifier;
+
+/**
+ * Helper class that builds and signs X.509 certificates.
+ *
+ * A CertificateBuilder is created with a default constructor, and then
+ * uses additional public methods to set the public key, desired validity
+ * dates, serial number and extensions.  It is expected that the caller will
+ * have generated the necessary key pairs prior to using a CertificateBuilder
+ * to generate certificates.
+ *
+ * The following methods are mandatory before calling build():
+ * <UL>
+ * <LI>{@link #setSubjectName(java.lang.String)}
+ * <LI>{@link #setPublicKey(java.security.PublicKey)}
+ * <LI>{@link #setNotBefore(java.util.Date)} and
+ * {@link #setNotAfter(java.util.Date)}, or
+ * {@link #setValidity(java.util.Date, java.util.Date)}
+ * <LI>{@link #setSerialNumber(java.math.BigInteger)}
+ * </UL><BR>
+ *
+ * Additionally, the caller can either provide a {@link List} of
+ * {@link Extension} objects, or use the helper classes to add specific
+ * extension types.
+ *
+ * When all required and desired parameters are set, the
+ * {@link #build(java.security.cert.X509Certificate, java.security.PrivateKey,
+ * java.lang.String)} method can be used to create the {@link X509Certificate}
+ * object.
+ *
+ * Multiple certificates may be cut from the same settings using subsequent
+ * calls to the build method.  Settings may be cleared using the
+ * {@link #reset()} method.
+ */
+public class CertificateBuilder {
+    private final CertificateFactory factory;
+
+    private X500Principal subjectName = null;
+    private BigInteger serialNumber = null;
+    private PublicKey publicKey = null;
+    private Date notBefore = null;
+    private Date notAfter = null;
+    private final Map<String, Extension> extensions = new HashMap<>();
+    private byte[] tbsCertBytes;
+    private byte[] signatureBytes;
+
+    /**
+     * Default constructor for a {@code CertificateBuilder} object.
+     *
+     * @throws CertificateException if the underlying {@link CertificateFactory}
+     * cannot be instantiated.
+     */
+    public CertificateBuilder() throws CertificateException {
+        factory = CertificateFactory.getInstance("X.509");
+    }
+
+    /**
+     * Set the subject name for the certificate.
+     *
+     * @param name An {@link X500Principal} to be used as the subject name
+     * on this certificate.
+     */
+    public void setSubjectName(X500Principal name) {
+        subjectName = name;
+    }
+
+    /**
+     * Set the subject name for the certificate.
+     *
+     * @param name The subject name in RFC 2253 format
+     */
+    public void setSubjectName(String name) {
+        subjectName = new X500Principal(name);
+    }
+
+    /**
+     * Set the public key for this certificate.
+     *
+     * @param pubKey The {@link PublicKey} to be used on this certificate.
+     */
+    public void setPublicKey(PublicKey pubKey) {
+        publicKey = Objects.requireNonNull(pubKey, "Caught null public key");
+    }
+
+    /**
+     * Set the NotBefore date on the certificate.
+     *
+     * @param nbDate A {@link Date} object specifying the start of the
+     * certificate validity period.
+     */
+    public void setNotBefore(Date nbDate) {
+        Objects.requireNonNull(nbDate, "Caught null notBefore date");
+        notBefore = (Date)nbDate.clone();
+    }
+
+    /**
+     * Set the NotAfter date on the certificate.
+     *
+     * @param naDate A {@link Date} object specifying the end of the
+     * certificate validity period.
+     */
+    public void setNotAfter(Date naDate) {
+        Objects.requireNonNull(naDate, "Caught null notAfter date");
+        notAfter = (Date)naDate.clone();
+    }
+
+    /**
+     * Set the validity period for the certificate
+     *
+     * @param nbDate A {@link Date} object specifying the start of the
+     * certificate validity period.
+     * @param naDate A {@link Date} object specifying the end of the
+     * certificate validity period.
+     */
+    public void setValidity(Date nbDate, Date naDate) {
+        setNotBefore(nbDate);
+        setNotAfter(naDate);
+    }
+
+    /**
+     * Set the serial number on the certificate.
+     *
+     * @param serial A serial number in {@link BigInteger} form.
+     */
+    public void setSerialNumber(BigInteger serial) {
+        Objects.requireNonNull(serial, "Caught null serial number");
+        serialNumber = serial;
+    }
+
+
+    /**
+     * Add a single extension to the certificate.
+     *
+     * @param ext The extension to be added.
+     */
+    public void addExtension(Extension ext) {
+        Objects.requireNonNull(ext, "Caught null extension");
+        extensions.put(ext.getId(), ext);
+    }
+
+    /**
+     * Add multiple extensions contained in a {@code List}.
+     *
+     * @param extList The {@link List} of extensions to be added to
+     * the certificate.
+     */
+    public void addExtensions(List<Extension> extList) {
+        Objects.requireNonNull(extList, "Caught null extension list");
+        for (Extension ext : extList) {
+            extensions.put(ext.getId(), ext);
+        }
+    }
+
+    /**
+     * Helper method to add DNSName types for the SAN extension
+     *
+     * @param dnsNames A {@code List} of names to add as DNSName types
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addSubjectAltNameDNSExt(List<String> dnsNames) throws IOException {
+        if (!dnsNames.isEmpty()) {
+            GeneralNames gNames = new GeneralNames();
+            for (String name : dnsNames) {
+                gNames.add(new GeneralName(new DNSName(name)));
+            }
+            addExtension(new SubjectAlternativeNameExtension(false,
+                    gNames));
+        }
+    }
+
+    /**
+     * Helper method to add one or more OCSP URIs to the Authority Info Access
+     * certificate extension.
+     *
+     * @param locations A list of one or more OCSP responder URIs as strings
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addAIAExt(List<String> locations)
+            throws IOException {
+        if (!locations.isEmpty()) {
+            List<AccessDescription> acDescList = new ArrayList<>();
+            for (String ocspUri : locations) {
+                acDescList.add(new AccessDescription(
+                        AccessDescription.Ad_OCSP_Id,
+                        new GeneralName(new URIName(ocspUri))));
+            }
+            addExtension(new AuthorityInfoAccessExtension(acDescList));
+        }
+    }
+
+    /**
+     * Set a Key Usage extension for the certificate.  The extension will
+     * be marked critical.
+     *
+     * @param bitSettings Boolean array for all nine bit settings in the order
+     * documented in RFC 5280 section 4.2.1.3.
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addKeyUsageExt(boolean[] bitSettings) throws IOException {
+        addExtension(new KeyUsageExtension(bitSettings));
+    }
+
+    /**
+     * Set the Basic Constraints Extension for a certificate.
+     *
+     * @param crit {@code true} if critical, {@code false} otherwise
+     * @param isCA {@code true} if the extension will be on a CA certificate,
+     * {@code false} otherwise
+     * @param maxPathLen The maximum path length issued by this CA.  Values
+     * less than zero will omit this field from the resulting extension and
+     * no path length constraint will be asserted.
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addBasicConstraintsExt(boolean crit, boolean isCA,
+            int maxPathLen) throws IOException {
+        addExtension(new BasicConstraintsExtension(crit, isCA, maxPathLen));
+    }
+
+    /**
+     * Add the Authority Key Identifier extension.
+     *
+     * @param authorityCert The certificate of the issuing authority.
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addAuthorityKeyIdExt(X509Certificate authorityCert)
+            throws IOException {
+        addAuthorityKeyIdExt(authorityCert.getPublicKey());
+    }
+
+    /**
+     * Add the Authority Key Identifier extension.
+     *
+     * @param authorityKey The public key of the issuing authority.
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addAuthorityKeyIdExt(PublicKey authorityKey) throws IOException {
+        KeyIdentifier kid = new KeyIdentifier(authorityKey);
+        addExtension(new AuthorityKeyIdentifierExtension(kid, null, null));
+    }
+
+    /**
+     * Add the Subject Key Identifier extension.
+     *
+     * @param subjectKey The public key to be used in the resulting certificate
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addSubjectKeyIdExt(PublicKey subjectKey) throws IOException {
+        byte[] keyIdBytes = new KeyIdentifier(subjectKey).getIdentifier();
+        addExtension(new SubjectKeyIdentifierExtension(keyIdBytes));
+    }
+
+    /**
+     * Add the Extended Key Usage extension.
+     *
+     * @param ekuOids A {@link List} of object identifiers in string form.
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    public void addExtendedKeyUsageExt(List<String> ekuOids)
+            throws IOException {
+        if (!ekuOids.isEmpty()) {
+            Vector<ObjectIdentifier> oidVector = new Vector<>();
+            for (String oid : ekuOids) {
+                oidVector.add(new ObjectIdentifier(oid));
+            }
+            addExtension(new ExtendedKeyUsageExtension(oidVector));
+        }
+    }
+
+    /**
+     * Clear all settings and return the {@code CertificateBuilder} to
+     * its default state.
+     */
+    public void reset() {
+        extensions.clear();
+        subjectName = null;
+        notBefore = null;
+        notAfter = null;
+        serialNumber = null;
+        publicKey = null;
+        signatureBytes = null;
+        tbsCertBytes = null;
+    }
+
+    /**
+     * Build the certificate.
+     *
+     * @param issuerCert The certificate of the issuing authority, or
+     * {@code null} if the resulting certificate is self-signed.
+     * @param issuerKey The private key of the issuing authority
+     * @param algName The signature algorithm name
+     *
+     * @return The resulting {@link X509Certificate}
+     *
+     * @throws IOException if an encoding error occurs.
+     * @throws CertificateException If the certificate cannot be generated
+     * by the underlying {@link CertificateFactory}
+     * @throws NoSuchAlgorithmException If an invalid signature algorithm
+     * is provided.
+     */
+    public X509Certificate build(X509Certificate issuerCert,
+            PrivateKey issuerKey, String algName)
+            throws IOException, CertificateException, NoSuchAlgorithmException {
+        // TODO: add some basic checks (key usage, basic constraints maybe)
+
+        AlgorithmId signAlg = AlgorithmId.get(algName);
+        byte[] encodedCert = encodeTopLevel(issuerCert, issuerKey, signAlg);
+        ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert);
+        return (X509Certificate)factory.generateCertificate(bais);
+    }
+
+    /**
+     * Encode the contents of the outer-most ASN.1 SEQUENCE:
+     *
+     * <PRE>
+     *  Certificate  ::=  SEQUENCE  {
+     *      tbsCertificate       TBSCertificate,
+     *      signatureAlgorithm   AlgorithmIdentifier,
+     *      signatureValue       BIT STRING  }
+     * </PRE>
+     *
+     * @param issuerCert The certificate of the issuing authority, or
+     * {@code null} if the resulting certificate is self-signed.
+     * @param issuerKey The private key of the issuing authority
+     * @param signAlg The signature algorithm object
+     *
+     * @return The DER-encoded X.509 certificate
+     *
+     * @throws CertificateException If an error occurs during the
+     * signing process.
+     * @throws IOException if an encoding error occurs.
+     */
+    private byte[] encodeTopLevel(X509Certificate issuerCert,
+            PrivateKey issuerKey, AlgorithmId signAlg)
+            throws CertificateException, IOException {
+        DerOutputStream outerSeq = new DerOutputStream();
+        DerOutputStream topLevelItems = new DerOutputStream();
+
+        tbsCertBytes = encodeTbsCert(issuerCert, signAlg);
+        topLevelItems.write(tbsCertBytes);
+        try {
+            signatureBytes = signCert(issuerKey, signAlg);
+        } catch (GeneralSecurityException ge) {
+            throw new CertificateException(ge);
+        }
+        signAlg.derEncode(topLevelItems);
+        topLevelItems.putBitString(signatureBytes);
+        outerSeq.write(DerValue.tag_Sequence, topLevelItems);
+
+        return outerSeq.toByteArray();
+    }
+
+    /**
+     * Encode the bytes for the TBSCertificate structure:
+     * <PRE>
+     *  TBSCertificate  ::=  SEQUENCE  {
+     *      version         [0]  EXPLICIT Version DEFAULT v1,
+     *      serialNumber         CertificateSerialNumber,
+     *      signature            AlgorithmIdentifier,
+     *      issuer               Name,
+     *      validity             Validity,
+     *      subject              Name,
+     *      subjectPublicKeyInfo SubjectPublicKeyInfo,
+     *      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+     *                        -- If present, version MUST be v2 or v3
+     *      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+     *                        -- If present, version MUST be v2 or v3
+     *      extensions      [3]  EXPLICIT Extensions OPTIONAL
+     *                        -- If present, version MUST be v3
+     *      }
+     *
+     * @param issuerCert The certificate of the issuing authority, or
+     * {@code null} if the resulting certificate is self-signed.
+     * @param signAlg The signature algorithm object
+     *
+     * @return The DER-encoded bytes for the TBSCertificate structure
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    private byte[] encodeTbsCert(X509Certificate issuerCert,
+            AlgorithmId signAlg) throws IOException {
+        DerOutputStream tbsCertSeq = new DerOutputStream();
+        DerOutputStream tbsCertItems = new DerOutputStream();
+
+        // Hardcode to V3
+        byte[] v3int = {0x02, 0x01, 0x02};
+        tbsCertItems.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
+                (byte)0), v3int);
+
+        // Serial Number
+        SerialNumber sn = new SerialNumber(serialNumber);
+        sn.encode(tbsCertItems);
+
+        // Algorithm ID
+        signAlg.derEncode(tbsCertItems);
+
+        // Issuer Name
+        if (issuerCert != null) {
+            tbsCertItems.write(
+                    issuerCert.getSubjectX500Principal().getEncoded());
+        } else {
+            // Self-signed
+            tbsCertItems.write(subjectName.getEncoded());
+        }
+
+        // Validity period (set as UTCTime)
+        DerOutputStream valSeq = new DerOutputStream();
+        valSeq.putUTCTime(notBefore);
+        valSeq.putUTCTime(notAfter);
+        tbsCertItems.write(DerValue.tag_Sequence, valSeq);
+
+        // Subject Name
+        tbsCertItems.write(subjectName.getEncoded());
+
+        // SubjectPublicKeyInfo
+        tbsCertItems.write(publicKey.getEncoded());
+
+        // TODO: Extensions!
+        encodeExtensions(tbsCertItems);
+
+        // Wrap it all up in a SEQUENCE and return the bytes
+        tbsCertSeq.write(DerValue.tag_Sequence, tbsCertItems);
+        return tbsCertSeq.toByteArray();
+    }
+
+    /**
+     * Encode the extensions segment for an X.509 Certificate:
+     *
+     * <PRE>
+     *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+     *
+     *  Extension  ::=  SEQUENCE  {
+     *      extnID      OBJECT IDENTIFIER,
+     *      critical    BOOLEAN DEFAULT FALSE,
+     *      extnValue   OCTET STRING
+     *                  -- contains the DER encoding of an ASN.1 value
+     *                  -- corresponding to the extension type identified
+     *                  -- by extnID
+     *      }
+     * </PRE>
+     *
+     * @param tbsStream The {@code DerOutputStream} that holds the
+     * TBSCertificate contents.
+     *
+     * @throws IOException if an encoding error occurs.
+     */
+    private void encodeExtensions(DerOutputStream tbsStream)
+            throws IOException {
+        DerOutputStream extSequence = new DerOutputStream();
+        DerOutputStream extItems = new DerOutputStream();
+
+        for (Extension ext : extensions.values()) {
+            ext.encode(extItems);
+        }
+        extSequence.write(DerValue.tag_Sequence, extItems);
+        tbsStream.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
+                (byte)3), extSequence);
+    }
+
+    /**
+     * Digitally sign the X.509 certificate.
+     *
+     * @param issuerKey The private key of the issuing authority
+     * @param signAlg The signature algorithm object
+     *
+     * @return The digital signature bytes.
+     *
+     * @throws GeneralSecurityException If any errors occur during the
+     * digital signature process.
+     */
+    private byte[] signCert(PrivateKey issuerKey, AlgorithmId signAlg)
+            throws GeneralSecurityException {
+        Signature sig = Signature.getInstance(signAlg.getName());
+        sig.initSign(issuerKey);
+        sig.update(tbsCertBytes);
+        return sig.sign();
+    }
+ }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/testlibrary/SimpleOCSPServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,1581 @@
+/*
+ * Copyright (c) 2015, 2016, 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.testlibrary;
+
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.security.cert.CRLReason;
+import java.security.cert.X509Certificate;
+import java.security.cert.Extension;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateEncodingException;
+import java.security.Signature;
+import java.util.*;
+import java.util.concurrent.*;
+import java.text.SimpleDateFormat;
+import java.math.BigInteger;
+
+import sun.security.x509.*;
+import sun.security.x509.PKIXExtensions;
+import sun.security.provider.certpath.ResponderId;
+import sun.security.provider.certpath.CertId;
+import sun.security.provider.certpath.OCSPResponse;
+import sun.security.provider.certpath.OCSPResponse.ResponseStatus;
+import sun.security.util.Debug;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+import sun.security.util.ObjectIdentifier;
+
+
+/**
+ * This is a simple OCSP server designed to listen and respond to incoming
+ * requests.
+ */
+public class SimpleOCSPServer {
+    private final Debug debug = Debug.getInstance("oserv");
+    private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
+            ObjectIdentifier.newInternal(
+                    new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
+    private static final SimpleDateFormat utcDateFmt =
+            new SimpleDateFormat("MMM dd yyyy, HH:mm:ss z");
+
+    static final int FREE_PORT = 0;
+
+    // CertStatus values
+    public static enum CertStatus {
+        CERT_STATUS_GOOD,
+        CERT_STATUS_REVOKED,
+        CERT_STATUS_UNKNOWN,
+    }
+
+    // Fields used for the networking portion of the responder
+    private ServerSocket servSocket;
+    private InetAddress listenAddress;
+    private int listenPort;
+
+    // Keystore information (certs, keys, etc.)
+    private KeyStore keystore;
+    private X509Certificate issuerCert;
+    private X509Certificate signerCert;
+    private PrivateKey signerKey;
+
+    // Fields used for the operational portions of the server
+    private boolean logEnabled = false;
+    private ExecutorService threadPool;
+    private volatile boolean started = false;
+    private volatile boolean serverReady = false;
+    private volatile boolean receivedShutdown = false;
+    private volatile boolean acceptConnections = true;
+    private volatile long delayMsec = 0;
+
+    // Fields used in the generation of responses
+    private long nextUpdateInterval = -1;
+    private Date nextUpdate = null;
+    private ResponderId respId;
+    private AlgorithmId sigAlgId;
+    private Map<CertId, CertStatusInfo> statusDb =
+            Collections.synchronizedMap(new HashMap<>());
+
+    /**
+     * Construct a SimpleOCSPServer using keystore, password, and alias
+     * parameters.
+     *
+     * @param ks the keystore to be used
+     * @param password the password to access key material in the keystore
+     * @param issuerAlias the alias of the issuer certificate
+     * @param signerAlias the alias of the signer certificate and key.  A
+     * value of {@code null} means that the {@code issuerAlias} will be used
+     * to look up the signer key.
+     *
+     * @throws GeneralSecurityException if there are problems accessing the
+     * keystore or finding objects within the keystore.
+     * @throws IOException if a {@code ResponderId} cannot be generated from
+     * the signer certificate.
+     */
+    public SimpleOCSPServer(KeyStore ks, String password, String issuerAlias,
+            String signerAlias) throws GeneralSecurityException, IOException {
+        this(null, FREE_PORT, ks, password, issuerAlias, signerAlias);
+    }
+
+    /**
+     * Construct a SimpleOCSPServer using specific network parameters,
+     * keystore, password, and alias.
+     *
+     * @param addr the address to bind the server to.  A value of {@code null}
+     * means the server will bind to all interfaces.
+     * @param port the port to listen on.  A value of {@code 0} will mean that
+     * the server will randomly pick an open ephemeral port to bind to.
+     * @param ks the keystore to be used
+     * @param password the password to access key material in the keystore
+     * @param issuerAlias the alias of the issuer certificate
+     * @param signerAlias the alias of the signer certificate and key.  A
+     * value of {@code null} means that the {@code issuerAlias} will be used
+     * to look up the signer key.
+     *
+     * @throws GeneralSecurityException if there are problems accessing the
+     * keystore or finding objects within the keystore.
+     * @throws IOException if a {@code ResponderId} cannot be generated from
+     * the signer certificate.
+     */
+    public SimpleOCSPServer(InetAddress addr, int port, KeyStore ks,
+            String password, String issuerAlias, String signerAlias)
+            throws GeneralSecurityException, IOException {
+        Objects.requireNonNull(ks, "Null keystore provided");
+        Objects.requireNonNull(issuerAlias, "Null issuerName provided");
+
+        utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT"));
+
+        keystore = ks;
+        issuerCert = (X509Certificate)ks.getCertificate(issuerAlias);
+        if (issuerCert == null) {
+            throw new IllegalArgumentException("Certificate for alias " +
+                    issuerAlias + " not found");
+        }
+
+        if (signerAlias != null) {
+            signerCert = (X509Certificate)ks.getCertificate(signerAlias);
+            if (signerCert == null) {
+                throw new IllegalArgumentException("Certificate for alias " +
+                    signerAlias + " not found");
+            }
+            signerKey = (PrivateKey)ks.getKey(signerAlias,
+                    password.toCharArray());
+            if (signerKey == null) {
+                throw new IllegalArgumentException("PrivateKey for alias " +
+                    signerAlias + " not found");
+            }
+        } else {
+            signerCert = issuerCert;
+            signerKey = (PrivateKey)ks.getKey(issuerAlias,
+                    password.toCharArray());
+            if (signerKey == null) {
+                throw new IllegalArgumentException("PrivateKey for alias " +
+                    issuerAlias + " not found");
+            }
+        }
+
+        sigAlgId = AlgorithmId.get("Sha256withRSA");
+        respId = new ResponderId(signerCert.getSubjectX500Principal());
+        listenAddress = addr;
+        listenPort = port;
+    }
+
+    /**
+     * Start the server.  The server will bind to the specified network
+     * address and begin listening for incoming connections.
+     *
+     * @throws IOException if any number of things go wonky.
+     */
+    public synchronized void start() throws IOException {
+        // You cannot start the server twice.
+        if (started) {
+            log("Server has already been started");
+            return;
+        } else {
+            started = true;
+        }
+
+        // Create and start the thread pool
+        threadPool = Executors.newFixedThreadPool(32, new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread t = Executors.defaultThreadFactory().newThread(r);
+                t.setDaemon(true);
+                return t;
+            }
+        });
+
+        threadPool.submit(new Runnable() {
+            @Override
+            public void run() {
+                try (ServerSocket sSock = new ServerSocket()) {
+                    servSocket = sSock;
+                    servSocket.setReuseAddress(true);
+                    servSocket.setSoTimeout(500);
+                    servSocket.bind(new InetSocketAddress(listenAddress,
+                            listenPort), 128);
+                    log("Listening on " + servSocket.getLocalSocketAddress());
+
+                    // Singal ready
+                    serverReady = true;
+
+                    // Update the listenPort with the new port number.  If
+                    // the server is restarted, it will bind to the same
+                    // port rather than picking a new one.
+                    listenPort = servSocket.getLocalPort();
+
+                    // Main dispatch loop
+                    while (!receivedShutdown) {
+                        try {
+                            Socket newConnection = servSocket.accept();
+                            if (!acceptConnections) {
+                                try {
+                                    log("Reject connection");
+                                    newConnection.close();
+                                } catch (IOException e) {
+                                    // ignore
+                                }
+                                continue;
+                            }
+                            threadPool.submit(new OcspHandler(newConnection));
+                        } catch (SocketTimeoutException timeout) {
+                            // Nothing to do here.  If receivedShutdown
+                            // has changed to true then the loop will
+                            // exit on its own.
+                        } catch (IOException ioe) {
+                            // Something bad happened, log and force a shutdown
+                            log("Unexpected Exception: " + ioe);
+                            stop();
+                        }
+                    }
+
+                    log("Shutting down...");
+                    threadPool.shutdown();
+                } catch (IOException ioe) {
+                    err(ioe);
+                } finally {
+                    // Reset state variables so the server can be restarted
+                    receivedShutdown = false;
+                    started = false;
+                    serverReady = false;
+                }
+            }
+        });
+    }
+
+    /**
+     * Make the OCSP server reject incoming connections.
+     */
+    public synchronized void rejectConnections() {
+        log("Reject OCSP connections");
+        acceptConnections = false;
+    }
+
+    /**
+     * Make the OCSP server accept incoming connections.
+     */
+    public synchronized void acceptConnections() {
+        log("Accept OCSP connections");
+        acceptConnections = true;
+    }
+
+
+    /**
+     * Stop the OCSP server.
+     */
+    public synchronized void stop() {
+        if (started) {
+            receivedShutdown = true;
+            log("Received shutdown notification");
+        }
+    }
+
+    /**
+     * Print {@code SimpleOCSPServer} operating parameters.
+     *
+     * @return the {@code SimpleOCSPServer} operating parameters in
+     * {@code String} form.
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("OCSP Server:\n");
+        sb.append("----------------------------------------------\n");
+        sb.append("issuer: ").append(issuerCert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("signer: ").append(signerCert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("ResponderId: ").append(respId).append("\n");
+        sb.append("----------------------------------------------");
+
+        return sb.toString();
+    }
+
+    /**
+     * Helpful debug routine to hex dump byte arrays.
+     *
+     * @param data the array of bytes to dump to stdout.
+     *
+     * @return the hexdump of the byte array
+     */
+    private static String dumpHexBytes(byte[] data) {
+        return dumpHexBytes(data, 16, "\n", " ");
+    }
+
+    /**
+     *
+     * @param data the array of bytes to dump to stdout.
+     * @param itemsPerLine the number of bytes to display per line
+     * if the {@code lineDelim} character is blank then all bytes will be
+     * printed on a single line.
+     * @param lineDelim the delimiter between lines
+     * @param itemDelim the delimiter between bytes
+     *
+     * @return The hexdump of the byte array
+     */
+    private static String dumpHexBytes(byte[] data, int itemsPerLine,
+            String lineDelim, String itemDelim) {
+        StringBuilder sb = new StringBuilder();
+        if (data != null) {
+            for (int i = 0; i < data.length; i++) {
+                if (i % itemsPerLine == 0 && i != 0) {
+                    sb.append(lineDelim);
+                }
+                sb.append(String.format("%02X", data[i])).append(itemDelim);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Enable or disable the logging feature.
+     *
+     * @param enable {@code true} to enable logging, {@code false} to
+     * disable it.  The setting must be activated before the server calls
+     * its start method.  Any calls after that have no effect.
+     */
+    public void enableLog(boolean enable) {
+        if (!started) {
+            logEnabled = enable;
+        }
+    }
+
+    /**
+     * Sets the nextUpdate interval.  Intervals will be calculated relative
+     * to the server startup time.  When first set, the nextUpdate date is
+     * calculated based on the current time plus the interval.  After that,
+     * calls to getNextUpdate() will return this date if it is still
+     * later than current time.  If not, the Date will be updated to the
+     * next interval that is later than current time.  This value must be set
+     * before the server has had its start method called.  Calls made after
+     * the server has been started have no effect.
+     *
+     * @param interval the recurring time interval in seconds used to
+     * calculate nextUpdate times.   A value less than or equal to 0 will
+     * disable the nextUpdate feature.
+     */
+    public synchronized void setNextUpdateInterval(long interval) {
+        if (!started) {
+            if (interval <= 0) {
+                nextUpdateInterval = -1;
+                nextUpdate = null;
+                log("nexUpdate support has been disabled");
+            } else {
+                nextUpdateInterval = interval * 1000;
+                nextUpdate = new Date(System.currentTimeMillis() +
+                        nextUpdateInterval);
+                log("nextUpdate set to " + nextUpdate);
+            }
+        }
+    }
+
+    /**
+     * Return the nextUpdate {@code Date} object for this server.  If the
+     * nextUpdate date has already passed, set a new nextUpdate based on
+     * the nextUpdate interval and return that date.
+     *
+     * @return a {@code Date} object set to the nextUpdate field for OCSP
+     * responses.
+     */
+    private synchronized Date getNextUpdate() {
+        if (nextUpdate != null && nextUpdate.before(new Date())) {
+            long nuEpochTime = nextUpdate.getTime();
+            long currentTime = System.currentTimeMillis();
+
+            // Keep adding nextUpdate intervals until you reach a date
+            // that is later than current time.
+            while (currentTime >= nuEpochTime) {
+                nuEpochTime += nextUpdateInterval;
+            }
+
+            // Set the nextUpdate for future threads
+            nextUpdate = new Date(nuEpochTime);
+            log("nextUpdate updated to new value: " + nextUpdate);
+        }
+        return nextUpdate;
+    }
+
+    /**
+     * Add entries into the responder's status database.
+     *
+     * @param newEntries a map of {@code CertStatusInfo} objects, keyed on
+     * their serial number (as a {@code BigInteger}).  All serial numbers
+     * are assumed to have come from this responder's issuer certificate.
+     *
+     * @throws IOException if a CertId cannot be generated.
+     */
+    public void updateStatusDb(Map<BigInteger, CertStatusInfo> newEntries)
+            throws IOException {
+         if (newEntries != null) {
+            for (BigInteger serial : newEntries.keySet()) {
+                CertStatusInfo info = newEntries.get(serial);
+                if (info != null) {
+                    CertId cid = new CertId(issuerCert,
+                            new SerialNumber(serial));
+                    statusDb.put(cid, info);
+                    log("Added entry for serial " + serial + "(" +
+                            info.getType() + ")");
+                }
+            }
+        }
+    }
+
+    /**
+     * Check the status database for revocation information one one or more
+     * certificates.
+     *
+     * @param reqList the list of {@code LocalSingleRequest} objects taken
+     * from the incoming OCSP request.
+     *
+     * @return a {@code Map} of {@code CertStatusInfo} objects keyed by their
+     * {@code CertId} values, for each single request passed in.  Those
+     * CertIds not found in the statusDb will have returned List members with
+     * a status of UNKNOWN.
+     */
+    private Map<CertId, CertStatusInfo> checkStatusDb(
+            List<LocalOcspRequest.LocalSingleRequest> reqList) {
+        // TODO figure out what, if anything to do with request extensions
+        Map<CertId, CertStatusInfo> returnMap = new HashMap<>();
+
+        for (LocalOcspRequest.LocalSingleRequest req : reqList) {
+            CertId cid = req.getCertId();
+            CertStatusInfo info = statusDb.get(cid);
+            if (info != null) {
+                log("Status for SN " + cid.getSerialNumber() + ": " +
+                        info.getType());
+                returnMap.put(cid, info);
+            } else {
+                log("Status for SN " + cid.getSerialNumber() +
+                        " not found, using CERT_STATUS_UNKNOWN");
+                returnMap.put(cid,
+                        new CertStatusInfo(CertStatus.CERT_STATUS_UNKNOWN));
+            }
+        }
+
+        return Collections.unmodifiableMap(returnMap);
+    }
+
+    /**
+     * Set the digital signature algorithm used to sign OCSP responses.
+     *
+     * @param algName The algorithm name
+     *
+     * @throws NoSuchAlgorithmException if the algorithm name is invalid.
+     */
+    public void setSignatureAlgorithm(String algName)
+            throws NoSuchAlgorithmException {
+        if (!started) {
+            sigAlgId = AlgorithmId.get(algName);
+        }
+    }
+
+    /**
+     * Get the port the OCSP server is running on.
+     *
+     * @return the port that the OCSP server is running on, or -1 if the
+     * server has not yet been bound to a port.
+     */
+    public int getPort() {
+        if (serverReady) {
+            InetSocketAddress inetSock =
+                    (InetSocketAddress)servSocket.getLocalSocketAddress();
+            return inetSock.getPort();
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Use to check if OCSP server is ready to accept connection.
+     *
+     * @return true if server ready, false otherwise
+     */
+    public boolean isServerReady() {
+        return serverReady;
+    }
+
+    /**
+     * Set a delay between the reception of the request and production of
+     * the response.
+     *
+     * @param delayMillis the number of milliseconds to wait before acting
+     * on the incoming request.
+     */
+    public void setDelay(long delayMillis) {
+        delayMsec = delayMillis > 0 ? delayMillis : 0;
+        if (delayMsec > 0) {
+            log("OCSP latency set to " + delayMsec + " milliseconds.");
+        } else {
+            log("OCSP latency disabled");
+        }
+    }
+
+    /**
+     * Log a message to stdout.
+     *
+     * @param message the message to log
+     */
+    private synchronized void log(String message) {
+        if (logEnabled || debug != null) {
+            System.out.println("[" + Thread.currentThread().getName() + "]: " +
+                    message);
+        }
+    }
+
+    /**
+     * Log an error message on the stderr stream.
+     *
+     * @param message the message to log
+     */
+    private static synchronized void err(String message) {
+        System.out.println("[" + Thread.currentThread().getName() + "]: " +
+                message);
+    }
+
+    /**
+     * Log exception information on the stderr stream.
+     *
+     * @param exc the exception to dump information about
+     */
+    private static synchronized void err(Throwable exc) {
+        System.out.print("[" + Thread.currentThread().getName() +
+                "]: Exception: ");
+        exc.printStackTrace(System.out);
+    }
+
+    /**
+     * The {@code CertStatusInfo} class defines an object used to return
+     * information from the internal status database.  The data in this
+     * object may be used to construct OCSP responses.
+     */
+    public static class CertStatusInfo {
+        private CertStatus certStatusType;
+        private CRLReason reason;
+        private Date revocationTime;
+
+        /**
+         * Create a Certificate status object by providing the status only.
+         * If the status is {@code REVOKED} then current time is assumed
+         * for the revocation time.
+         *
+         * @param statType the status for this entry.
+         */
+        public CertStatusInfo(CertStatus statType) {
+            this(statType, null, null);
+        }
+
+        /**
+         * Create a CertStatusInfo providing both type and revocation date
+         * (if applicable).
+         *
+         * @param statType the status for this entry.
+         * @param revDate if applicable, the date that revocation took place.
+         * A value of {@code null} indicates that current time should be used.
+         * If the value of {@code statType} is not {@code CERT_STATUS_REVOKED},
+         * then the {@code revDate} parameter is ignored.
+         */
+        public CertStatusInfo(CertStatus statType, Date revDate) {
+            this(statType, revDate, null);
+        }
+
+        /**
+         * Create a CertStatusInfo providing type, revocation date
+         * (if applicable) and revocation reason.
+         *
+         * @param statType the status for this entry.
+         * @param revDate if applicable, the date that revocation took place.
+         * A value of {@code null} indicates that current time should be used.
+         * If the value of {@code statType} is not {@code CERT_STATUS_REVOKED},
+         * then the {@code revDate} parameter is ignored.
+         * @param revReason the reason the certificate was revoked.  A value of
+         * {@code null} means that no reason was provided.
+         */
+        public CertStatusInfo(CertStatus statType, Date revDate,
+                CRLReason revReason) {
+            Objects.requireNonNull(statType, "Cert Status must be non-null");
+            certStatusType = statType;
+            switch (statType) {
+                case CERT_STATUS_GOOD:
+                case CERT_STATUS_UNKNOWN:
+                    revocationTime = null;
+                    break;
+                case CERT_STATUS_REVOKED:
+                    revocationTime = revDate != null ? (Date)revDate.clone() :
+                            new Date();
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unknown status type: " +
+                            statType);
+            }
+        }
+
+        /**
+         * Get the cert status type
+         *
+         * @return the status applied to this object (e.g.
+         * {@code CERT_STATUS_GOOD}, {@code CERT_STATUS_UNKNOWN}, etc.)
+         */
+        public CertStatus getType() {
+            return certStatusType;
+        }
+
+        /**
+         * Get the revocation time (if applicable).
+         *
+         * @return the revocation time as a {@code Date} object, or
+         * {@code null} if not applicable (i.e. if the certificate hasn't been
+         * revoked).
+         */
+        public Date getRevocationTime() {
+            return (revocationTime != null ? (Date)revocationTime.clone() :
+                    null);
+        }
+
+        /**
+         * Get the revocation reason.
+         *
+         * @return the revocation reason, or {@code null} if one was not
+         * provided.
+         */
+        public CRLReason getRevocationReason() {
+            return reason;
+        }
+    }
+
+    /**
+     * Runnable task that handles incoming OCSP Requests and returns
+     * responses.
+     */
+    private class OcspHandler implements Runnable {
+        private final Socket sock;
+        InetSocketAddress peerSockAddr;
+
+        /**
+         * Construct an {@code OcspHandler}.
+         *
+         * @param incomingSocket the socket the server created on accept()
+         */
+        private OcspHandler(Socket incomingSocket) {
+            sock = incomingSocket;
+        }
+
+        /**
+         * Run the OCSP Request parser and construct a response to be sent
+         * back to the client.
+         */
+        @Override
+        public void run() {
+            // If we have implemented a delay to simulate network latency
+            // wait out the delay here before any other processing.
+            try {
+                if (delayMsec > 0) {
+                    Thread.sleep(delayMsec);
+                }
+            } catch (InterruptedException ie) {
+                // Just log the interrupted sleep
+                log("Delay of " + delayMsec + " milliseconds was interrupted");
+            }
+
+            try (Socket ocspSocket = sock;
+                    InputStream in = ocspSocket.getInputStream();
+                    OutputStream out = ocspSocket.getOutputStream()) {
+                peerSockAddr =
+                        (InetSocketAddress)ocspSocket.getRemoteSocketAddress();
+                log("Received incoming connection from " + peerSockAddr);
+                String[] headerTokens = readLine(in).split(" ");
+                LocalOcspRequest ocspReq = null;
+                LocalOcspResponse ocspResp = null;
+                ResponseStatus respStat = ResponseStatus.INTERNAL_ERROR;
+                try {
+                    if (headerTokens[0] != null) {
+                        switch (headerTokens[0]) {
+                            case "POST":
+                                    ocspReq = parseHttpOcspPost(in);
+                                break;
+                            case "GET":
+                                // req = parseHttpOcspGet(in);
+                                // TODO implement the GET parsing
+                                throw new IOException("GET method unsupported");
+                            default:
+                                respStat = ResponseStatus.MALFORMED_REQUEST;
+                                throw new IOException("Not a GET or POST");
+                        }
+                    } else {
+                        respStat = ResponseStatus.MALFORMED_REQUEST;
+                        throw new IOException("Unable to get HTTP method");
+                    }
+
+                    if (ocspReq != null) {
+                        log(ocspReq.toString());
+                        // Get responses for all CertIds in the request
+                        Map<CertId, CertStatusInfo> statusMap =
+                                checkStatusDb(ocspReq.getRequests());
+                        if (statusMap.isEmpty()) {
+                            respStat = ResponseStatus.UNAUTHORIZED;
+                        } else {
+                            ocspResp = new LocalOcspResponse(
+                                    ResponseStatus.SUCCESSFUL, statusMap,
+                                    ocspReq.getExtensions());
+                        }
+                    } else {
+                        respStat = ResponseStatus.MALFORMED_REQUEST;
+                        throw new IOException("Found null request");
+                    }
+                } catch (IOException | RuntimeException exc) {
+                    err(exc);
+                }
+                if (ocspResp == null) {
+                    ocspResp = new LocalOcspResponse(respStat);
+                }
+                sendResponse(out, ocspResp);
+            } catch (IOException | CertificateException exc) {
+                err(exc);
+            }
+        }
+
+        /**
+         * Send an OCSP response on an {@code OutputStream}.
+         *
+         * @param out the {@code OutputStream} on which to send the response.
+         * @param resp the OCSP response to send.
+         *
+         * @throws IOException if an encoding error occurs.
+         */
+        public void sendResponse(OutputStream out, LocalOcspResponse resp)
+                throws IOException {
+            StringBuilder sb = new StringBuilder();
+
+            byte[] respBytes;
+            try {
+                respBytes = resp.getBytes();
+            } catch (RuntimeException re) {
+                err(re);
+                return;
+            }
+
+            sb.append("HTTP/1.0 200 OK\r\n");
+            sb.append("Content-Type: application/ocsp-response\r\n");
+            sb.append("Content-Length: ").append(respBytes.length);
+            sb.append("\r\n\r\n");
+
+            out.write(sb.toString().getBytes("UTF-8"));
+            out.write(respBytes);
+            log(resp.toString());
+        }
+
+        /**
+         * Parse the incoming HTTP POST of an OCSP Request.
+         *
+         * @param inStream the input stream from the socket bound to this
+         * {@code OcspHandler}.
+         *
+         * @return the OCSP Request as a {@code LocalOcspRequest}
+         *
+         * @throws IOException if there are network related issues or problems
+         * occur during parsing of the OCSP request.
+         * @throws CertificateException if one or more of the certificates in
+         * the OCSP request cannot be read/parsed.
+         */
+        private LocalOcspRequest parseHttpOcspPost(InputStream inStream)
+                throws IOException, CertificateException {
+            boolean endOfHeader = false;
+            boolean properContentType = false;
+            int length = -1;
+
+            while (!endOfHeader) {
+                String[] lineTokens = readLine(inStream).split(" ");
+                if (lineTokens[0].isEmpty()) {
+                    endOfHeader = true;
+                } else if (lineTokens[0].equalsIgnoreCase("Content-Type:")) {
+                    if (lineTokens[1] == null ||
+                            !lineTokens[1].equals(
+                                    "application/ocsp-request")) {
+                        log("Unknown Content-Type: " +
+                                (lineTokens[1] != null ?
+                                        lineTokens[1] : "<NULL>"));
+                        return null;
+                    } else {
+                        properContentType = true;
+                        log("Content-Type = " + lineTokens[1]);
+                    }
+                } else if (lineTokens[0].equalsIgnoreCase("Content-Length:")) {
+                    if (lineTokens[1] != null) {
+                        length = Integer.parseInt(lineTokens[1]);
+                        log("Content-Length = " + length);
+                    }
+                }
+            }
+
+            // Okay, make sure we got what we needed from the header, then
+            // read the remaining OCSP Request bytes
+            if (properContentType && length >= 0) {
+                byte[] ocspBytes = new byte[length];
+                inStream.read(ocspBytes);
+                return new LocalOcspRequest(ocspBytes);
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Read a line of text that is CRLF-delimited.
+         *
+         * @param is the {@code InputStream} tied to the socket
+         * for this {@code OcspHandler}
+         *
+         * @return a {@code String} consisting of the line of text
+         * read from the stream with the CRLF stripped.
+         *
+         * @throws IOException if any I/O error occurs.
+         */
+        private String readLine(InputStream is) throws IOException {
+            PushbackInputStream pbis = new PushbackInputStream(is);
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            boolean done = false;
+            while (!done) {
+                byte b = (byte)pbis.read();
+                if (b == '\r') {
+                    byte bNext = (byte)pbis.read();
+                    if (bNext == '\n' || bNext == -1) {
+                        done = true;
+                    } else {
+                        pbis.unread(bNext);
+                        bos.write(b);
+                    }
+                } else if (b == -1) {
+                    done = true;
+                } else {
+                    bos.write(b);
+                }
+            }
+
+            return new String(bos.toByteArray(), "UTF-8");
+        }
+    }
+
+
+    /**
+     * Simple nested class to handle OCSP requests without making
+     * changes to sun.security.provider.certpath.OCSPRequest
+     */
+    public class LocalOcspRequest {
+
+        private byte[] nonce;
+        private byte[] signature = null;
+        private AlgorithmId algId = null;
+        private int version = 0;
+        private GeneralName requestorName = null;
+        private Map<String, Extension> extensions = Collections.emptyMap();
+        private final List<LocalSingleRequest> requestList = new ArrayList<>();
+        private final List<X509Certificate> certificates = new ArrayList<>();
+
+        /**
+         * Construct a {@code LocalOcspRequest} from its DER encoding.
+         *
+         * @param requestBytes the DER-encoded bytes
+         *
+         * @throws IOException if decoding errors occur
+         * @throws CertificateException if certificates are found in the
+         * OCSP request and they do not parse correctly.
+         */
+        private LocalOcspRequest(byte[] requestBytes) throws IOException,
+                CertificateException {
+            Objects.requireNonNull(requestBytes, "Received null input");
+
+            DerInputStream dis = new DerInputStream(requestBytes);
+
+            // Parse the top-level structure, it should have no more than
+            // two elements.
+            DerValue[] topStructs = dis.getSequence(2);
+            for (DerValue dv : topStructs) {
+                if (dv.tag == DerValue.tag_Sequence) {
+                    parseTbsRequest(dv);
+                } else if (dv.isContextSpecific((byte)0)) {
+                    parseSignature(dv);
+                } else {
+                    throw new IOException("Unknown tag at top level: " +
+                            dv.tag);
+                }
+            }
+        }
+
+        /**
+         * Parse the signature block from an OCSP request
+         *
+         * @param sigSequence a {@code DerValue} containing the signature
+         * block at the outer sequence datum.
+         *
+         * @throws IOException if any non-certificate-based parsing errors occur
+         * @throws CertificateException if certificates are found in the
+         * OCSP request and they do not parse correctly.
+         */
+        private void parseSignature(DerValue sigSequence)
+                throws IOException, CertificateException {
+            DerValue[] sigItems = sigSequence.data.getSequence(3);
+            if (sigItems.length != 3) {
+                throw new IOException("Invalid number of signature items: " +
+                        "expected 3, got " + sigItems.length);
+            }
+
+            algId = AlgorithmId.parse(sigItems[0]);
+            signature = sigItems[1].getBitString();
+
+            if (sigItems[2].isContextSpecific((byte)0)) {
+                DerValue[] certDerItems = sigItems[2].data.getSequence(4);
+                int i = 0;
+                for (DerValue dv : certDerItems) {
+                    X509Certificate xc = new X509CertImpl(dv);
+                    certificates.add(xc);
+                }
+            } else {
+                throw new IOException("Invalid tag in signature block: " +
+                    sigItems[2].tag);
+            }
+        }
+
+        /**
+         * Parse the to-be-signed request data
+         *
+         * @param tbsReqSeq a {@code DerValue} object containing the to-be-
+         * signed OCSP request at the outermost SEQUENCE tag.
+         * @throws IOException if any parsing errors occur
+         */
+        private void parseTbsRequest(DerValue tbsReqSeq) throws IOException {
+            while (tbsReqSeq.data.available() > 0) {
+                DerValue dv = tbsReqSeq.data.getDerValue();
+                if (dv.isContextSpecific((byte)0)) {
+                    // The version was explicitly called out
+                    version = dv.data.getInteger();
+                } else if (dv.isContextSpecific((byte)1)) {
+                    // A GeneralName was provided
+                    requestorName = new GeneralName(dv.data.getDerValue());
+                } else if (dv.isContextSpecific((byte)2)) {
+                    // Parse the extensions
+                    DerValue[] extItems = dv.data.getSequence(2);
+                    extensions = parseExtensions(extItems);
+                } else if (dv.tag == DerValue.tag_Sequence) {
+                    while (dv.data.available() > 0) {
+                        requestList.add(new LocalSingleRequest(dv.data));
+                    }
+                }
+            }
+        }
+
+        /**
+         * Parse a SEQUENCE of extensions.  This routine is used both
+         * at the overall request level and down at the singleRequest layer.
+         *
+         * @param extDerItems an array of {@code DerValue} items, each one
+         * consisting of a DER-encoded extension.
+         *
+         * @return a {@code Map} of zero or more extensions,
+         * keyed by its object identifier in {@code String} form.
+         *
+         * @throws IOException if any parsing errors occur.
+         */
+        private Map<String, Extension> parseExtensions(DerValue[] extDerItems)
+                throws IOException {
+            Map<String, Extension> extMap = new HashMap<>();
+
+            if (extDerItems != null && extDerItems.length != 0) {
+                for (DerValue extDerVal : extDerItems) {
+                    sun.security.x509.Extension ext =
+                            new sun.security.x509.Extension(extDerVal);
+                    extMap.put(ext.getId(), ext);
+                }
+            }
+
+            return extMap;
+        }
+
+        /**
+         * Return the list of single request objects in this OCSP request.
+         *
+         * @return an unmodifiable {@code List} of zero or more requests.
+         */
+        private List<LocalSingleRequest> getRequests() {
+            return Collections.unmodifiableList(requestList);
+        }
+
+        /**
+         * Return the list of X.509 Certificates in this OCSP request.
+         *
+         * @return an unmodifiable {@code List} of zero or more
+         * {@cpde X509Certificate} objects.
+         */
+        private List<X509Certificate> getCertificates() {
+            return Collections.unmodifiableList(certificates);
+        }
+
+        /**
+         * Return the map of OCSP request extensions.
+         *
+         * @return an unmodifiable {@code Map} of zero or more
+         * {@code Extension} objects, keyed by their object identifiers
+         * in {@code String} form.
+         */
+        private Map<String, Extension> getExtensions() {
+            return Collections.unmodifiableMap(extensions);
+        }
+
+        /**
+         * Display the {@code LocalOcspRequest} in human readable form.
+         *
+         * @return a {@code String} representation of the
+         * {@code LocalOcspRequest}
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append(String.format("OCSP Request: Version %d (0x%X)",
+                    version + 1, version)).append("\n");
+            if (requestorName != null) {
+                sb.append("Requestor Name: ").append(requestorName).
+                        append("\n");
+            }
+
+            int requestCtr = 0;
+            for (LocalSingleRequest lsr : requestList) {
+                sb.append("Request [").append(requestCtr++).append("]\n");
+                sb.append(lsr).append("\n");
+            }
+            if (!extensions.isEmpty()) {
+                sb.append("Extensions (").append(extensions.size()).
+                        append(")\n");
+                for (Extension ext : extensions.values()) {
+                    sb.append("\t").append(ext).append("\n");
+                }
+            }
+            if (signature != null) {
+                sb.append("Signature: ").append(algId).append("\n");
+                sb.append(dumpHexBytes(signature)).append("\n");
+                int certCtr = 0;
+                for (X509Certificate cert : certificates) {
+                    sb.append("Certificate [").append(certCtr++).append("]").
+                            append("\n");
+                    sb.append("\tSubject: ");
+                    sb.append(cert.getSubjectX500Principal()).append("\n");
+                    sb.append("\tIssuer: ");
+                    sb.append(cert.getIssuerX500Principal()).append("\n");
+                    sb.append("\tSerial: ").append(cert.getSerialNumber());
+                }
+            }
+
+            return sb.toString();
+        }
+
+        /**
+         * Inner class designed to handle the decoding/representation of
+         * single requests within a {@code LocalOcspRequest} object.
+         */
+        public class LocalSingleRequest {
+            private final CertId cid;
+            private Map<String, Extension> extensions = Collections.emptyMap();
+
+            private LocalSingleRequest(DerInputStream dis)
+                    throws IOException {
+                DerValue[] srItems = dis.getSequence(2);
+
+                // There should be 1, possibly 2 DerValue items
+                if (srItems.length == 1 || srItems.length == 2) {
+                    // The first parsable item should be the mandatory CertId
+                    cid = new CertId(srItems[0].data);
+                    if (srItems.length == 2) {
+                        if (srItems[1].isContextSpecific((byte)0)) {
+                            DerValue[] extDerItems = srItems[1].data.getSequence(2);
+                            extensions = parseExtensions(extDerItems);
+                        } else {
+                            throw new IOException("Illegal tag in Request " +
+                                    "extensions: " + srItems[1].tag);
+                        }
+                    }
+                } else {
+                    throw new IOException("Invalid number of items in " +
+                            "Request (" + srItems.length + ")");
+                }
+            }
+
+            /**
+             * Get the {@code CertId} for this single request.
+             *
+             * @return the {@code CertId} for this single request.
+             */
+            private CertId getCertId() {
+                return cid;
+            }
+
+            /**
+             * Return the map of single request extensions.
+             *
+             * @return an unmodifiable {@code Map} of zero or more
+             * {@code Extension} objects, keyed by their object identifiers
+             * in {@code String} form.
+             */
+            private Map<String, Extension> getExtensions() {
+                return Collections.unmodifiableMap(extensions);
+            }
+
+            /**
+             * Display the {@code LocalSingleRequest} in human readable form.
+             *
+             * @return a {@code String} representation of the
+             * {@code LocalSingleRequest}
+             */
+            @Override
+            public String toString() {
+                StringBuilder sb = new StringBuilder();
+                sb.append("CertId, Algorithm = ");
+                sb.append(cid.getHashAlgorithm()).append("\n");
+                sb.append("\tIssuer Name Hash: ");
+                sb.append(dumpHexBytes(cid.getIssuerNameHash(), 256, "", ""));
+                sb.append("\n");
+                sb.append("\tIssuer Key Hash: ");
+                sb.append(dumpHexBytes(cid.getIssuerKeyHash(), 256, "", ""));
+                sb.append("\n");
+                sb.append("\tSerial Number: ").append(cid.getSerialNumber());
+                if (!extensions.isEmpty()) {
+                    sb.append("Extensions (").append(extensions.size()).
+                            append(")\n");
+                    for (Extension ext : extensions.values()) {
+                        sb.append("\t").append(ext).append("\n");
+                    }
+                }
+
+                return sb.toString();
+            }
+        }
+    }
+
+    /**
+     * Simple nested class to handle OCSP requests without making
+     * changes to sun.security.provider.certpath.OCSPResponse
+     */
+    public class LocalOcspResponse {
+        private final int version = 0;
+        private final OCSPResponse.ResponseStatus responseStatus;
+        private final Map<CertId, CertStatusInfo> respItemMap;
+        private final Date producedAtDate;
+        private final List<LocalSingleResponse> singleResponseList =
+                new ArrayList<>();
+        private final Map<String, Extension> responseExtensions;
+        private byte[] signature;
+        private final List<X509Certificate> certificates;
+        private final byte[] encodedResponse;
+
+        /**
+         * Constructor for the generation of non-successful responses
+         *
+         * @param respStat the OCSP response status.
+         *
+         * @throws IOException if an error happens during encoding
+         * @throws NullPointerException if {@code respStat} is {@code null}
+         * or {@code respStat} is successful.
+         */
+        public LocalOcspResponse(OCSPResponse.ResponseStatus respStat)
+                throws IOException {
+            this(respStat, null, null);
+        }
+
+        /**
+         * Construct a response from a list of certificate
+         * status objects and extensions.
+         *
+         * @param respStat the status of the entire response
+         * @param itemMap a {@code Map} of {@code CertId} objects and their
+         * respective revocation statuses from the server's response DB.
+         * @param reqExtensions a {@code Map} of request extensions
+         *
+         * @throws IOException if an error happens during encoding
+         * @throws NullPointerException if {@code respStat} is {@code null}
+         * or {@code respStat} is successful, and a {@code null} {@code itemMap}
+         * has been provided.
+         */
+        public LocalOcspResponse(OCSPResponse.ResponseStatus respStat,
+                Map<CertId, CertStatusInfo> itemMap,
+                Map<String, Extension> reqExtensions) throws IOException {
+            responseStatus = Objects.requireNonNull(respStat,
+                    "Illegal null response status");
+            if (responseStatus == ResponseStatus.SUCCESSFUL) {
+                respItemMap = Objects.requireNonNull(itemMap,
+                        "SUCCESSFUL responses must have a response map");
+                producedAtDate = new Date();
+
+                // Turn the answerd from the response DB query into a list
+                // of single responses.
+                for (CertId id : itemMap.keySet()) {
+                    singleResponseList.add(
+                            new LocalSingleResponse(id, itemMap.get(id)));
+                }
+
+                responseExtensions = setResponseExtensions(reqExtensions);
+                certificates = new ArrayList<>();
+                if (signerCert != issuerCert) {
+                    certificates.add(signerCert);
+                }
+                certificates.add(issuerCert);
+            } else {
+                respItemMap = null;
+                producedAtDate = null;
+                responseExtensions = null;
+                certificates = null;
+            }
+            encodedResponse = this.getBytes();
+        }
+
+        /**
+         * Set the response extensions based on the request extensions
+         * that were received.  Right now, this is limited to the
+         * OCSP nonce extension.
+         *
+         * @param reqExts a {@code Map} of zero or more request extensions
+         *
+         * @return a {@code Map} of zero or more response extensions, keyed
+         * by the extension object identifier in {@code String} form.
+         */
+        private Map<String, Extension> setResponseExtensions(
+                Map<String, Extension> reqExts) {
+            Map<String, Extension> respExts = new HashMap<>();
+            String ocspNonceStr = PKIXExtensions.OCSPNonce_Id.toString();
+
+            if (reqExts != null) {
+                for (String id : reqExts.keySet()) {
+                    if (id.equals(ocspNonceStr)) {
+                        // We found a nonce, add it into the response extensions
+                        Extension ext = reqExts.get(id);
+                        if (ext != null) {
+                            respExts.put(id, ext);
+                            log("Added OCSP Nonce to response");
+                        } else {
+                            log("Error: Found nonce entry, but found null " +
+                                    "value.  Skipping");
+                        }
+                    }
+                }
+            }
+
+            return respExts;
+        }
+
+        /**
+         * Get the DER-encoded response bytes for this response
+         *
+         * @return a byte array containing the DER-encoded bytes for
+         * the response
+         *
+         * @throws IOException if any encoding errors occur
+         */
+        private byte[] getBytes() throws IOException {
+            DerOutputStream outerSeq = new DerOutputStream();
+            DerOutputStream responseStream = new DerOutputStream();
+            responseStream.putEnumerated(responseStatus.ordinal());
+            if (responseStatus == ResponseStatus.SUCCESSFUL &&
+                    respItemMap != null) {
+                encodeResponseBytes(responseStream);
+            }
+
+            // Commit the outermost sequence bytes
+            outerSeq.write(DerValue.tag_Sequence, responseStream);
+            return outerSeq.toByteArray();
+        }
+
+        private void encodeResponseBytes(DerOutputStream responseStream)
+                throws IOException {
+            DerOutputStream explicitZero = new DerOutputStream();
+            DerOutputStream respItemStream = new DerOutputStream();
+
+            respItemStream.putOID(OCSP_BASIC_RESPONSE_OID);
+
+            byte[] basicOcspBytes = encodeBasicOcspResponse();
+            respItemStream.putOctetString(basicOcspBytes);
+            explicitZero.write(DerValue.tag_Sequence, respItemStream);
+            responseStream.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                    true, (byte)0), explicitZero);
+        }
+
+        private byte[] encodeBasicOcspResponse() throws IOException {
+            DerOutputStream outerSeq = new DerOutputStream();
+            DerOutputStream basicORItemStream = new DerOutputStream();
+
+            // Encode the tbsResponse
+            byte[] tbsResponseBytes = encodeTbsResponse();
+            basicORItemStream.write(tbsResponseBytes);
+
+            try {
+                sigAlgId.derEncode(basicORItemStream);
+
+                // Create the signature
+                Signature sig = Signature.getInstance(sigAlgId.getName());
+                sig.initSign(signerKey);
+                sig.update(tbsResponseBytes);
+                signature = sig.sign();
+                basicORItemStream.putBitString(signature);
+            } catch (GeneralSecurityException exc) {
+                err(exc);
+                throw new IOException(exc);
+            }
+
+            // Add certificates
+            try {
+                DerOutputStream certStream = new DerOutputStream();
+                ArrayList<DerValue> certList = new ArrayList<>();
+                if (signerCert != issuerCert) {
+                    certList.add(new DerValue(signerCert.getEncoded()));
+                }
+                certList.add(new DerValue(issuerCert.getEncoded()));
+                DerValue[] dvals = new DerValue[certList.size()];
+                certStream.putSequence(certList.toArray(dvals));
+                basicORItemStream.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                        true, (byte)0), certStream);
+            } catch (CertificateEncodingException cex) {
+                err(cex);
+                throw new IOException(cex);
+            }
+
+            // Commit the outermost sequence bytes
+            outerSeq.write(DerValue.tag_Sequence, basicORItemStream);
+            return outerSeq.toByteArray();
+        }
+
+        private byte[] encodeTbsResponse() throws IOException {
+            DerOutputStream outerSeq = new DerOutputStream();
+            DerOutputStream tbsStream = new DerOutputStream();
+
+            // Note: We're not going explicitly assert the version
+            tbsStream.write(respId.getEncoded());
+            tbsStream.putGeneralizedTime(producedAtDate);
+
+            // Sequence of responses
+            encodeSingleResponses(tbsStream);
+
+            // TODO: add response extension support
+            encodeExtensions(tbsStream);
+
+            outerSeq.write(DerValue.tag_Sequence, tbsStream);
+            return outerSeq.toByteArray();
+        }
+
+        private void encodeSingleResponses(DerOutputStream tbsStream)
+                throws IOException {
+            DerValue[] srDerVals = new DerValue[singleResponseList.size()];
+            int srDvCtr = 0;
+
+            for (LocalSingleResponse lsr : singleResponseList) {
+                srDerVals[srDvCtr++] = new DerValue(lsr.getBytes());
+            }
+
+            tbsStream.putSequence(srDerVals);
+        }
+
+        private void encodeExtensions(DerOutputStream tbsStream)
+                throws IOException {
+            DerOutputStream extSequence = new DerOutputStream();
+            DerOutputStream extItems = new DerOutputStream();
+
+            for (Extension ext : responseExtensions.values()) {
+                ext.encode(extItems);
+            }
+            extSequence.write(DerValue.tag_Sequence, extItems);
+            tbsStream.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
+                    (byte)1), extSequence);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+
+            sb.append("OCSP Response: ").append(responseStatus).append("\n");
+            if (responseStatus == ResponseStatus.SUCCESSFUL) {
+                sb.append("Response Type: ").
+                        append(OCSP_BASIC_RESPONSE_OID.toString()).append("\n");
+                sb.append(String.format("Version: %d (0x%X)", version + 1,
+                        version)).append("\n");
+                sb.append("Responder Id: ").append(respId.toString()).
+                        append("\n");
+                sb.append("Produced At: ").
+                        append(utcDateFmt.format(producedAtDate)).append("\n");
+
+                int srCtr = 0;
+                for (LocalSingleResponse lsr : singleResponseList) {
+                    sb.append("SingleResponse [").append(srCtr++).append("]\n");
+                    sb.append(lsr);
+                }
+
+                if (!responseExtensions.isEmpty()) {
+                    sb.append("Extensions (").append(responseExtensions.size()).
+                            append(")\n");
+                    for (Extension ext : responseExtensions.values()) {
+                        sb.append("\t").append(ext).append("\n");
+                    }
+                } else {
+                    sb.append("\n");
+                }
+
+                if (signature != null) {
+                    sb.append("Signature: ").append(sigAlgId).append("\n");
+                    sb.append(dumpHexBytes(signature)).append("\n");
+                    int certCtr = 0;
+                    for (X509Certificate cert : certificates) {
+                        sb.append("Certificate [").append(certCtr++).append("]").
+                                append("\n");
+                        sb.append("\tSubject: ");
+                        sb.append(cert.getSubjectX500Principal()).append("\n");
+                        sb.append("\tIssuer: ");
+                        sb.append(cert.getIssuerX500Principal()).append("\n");
+                        sb.append("\tSerial: ").append(cert.getSerialNumber());
+                        sb.append("\n");
+                    }
+                }
+            }
+
+            return sb.toString();
+        }
+
+        private class LocalSingleResponse {
+            private final CertId certId;
+            private final CertStatusInfo csInfo;
+            private final Date thisUpdate;
+            private final Date lsrNextUpdate;
+            private final Map<String, Extension> singleExtensions;
+
+            public LocalSingleResponse(CertId cid, CertStatusInfo info) {
+                certId = Objects.requireNonNull(cid, "CertId must be non-null");
+                csInfo = Objects.requireNonNull(info,
+                        "CertStatusInfo must be non-null");
+
+                // For now, we'll keep things simple and make the thisUpdate
+                // field the same as the producedAt date.
+                thisUpdate = producedAtDate;
+                lsrNextUpdate = getNextUpdate();
+
+                // TODO Add extensions support
+                singleExtensions = Collections.emptyMap();
+            }
+
+            @Override
+            public String toString() {
+                StringBuilder sb = new StringBuilder();
+                sb.append("Certificate Status: ").append(csInfo.getType());
+                sb.append("\n");
+                if (csInfo.getType() == CertStatus.CERT_STATUS_REVOKED) {
+                    sb.append("Revocation Time: ");
+                    sb.append(utcDateFmt.format(csInfo.getRevocationTime()));
+                    sb.append("\n");
+                    if (csInfo.getRevocationReason() != null) {
+                        sb.append("Revocation Reason: ");
+                        sb.append(csInfo.getRevocationReason()).append("\n");
+                    }
+                }
+
+                sb.append("CertId, Algorithm = ");
+                sb.append(certId.getHashAlgorithm()).append("\n");
+                sb.append("\tIssuer Name Hash: ");
+                sb.append(dumpHexBytes(certId.getIssuerNameHash(), 256, "", ""));
+                sb.append("\n");
+                sb.append("\tIssuer Key Hash: ");
+                sb.append(dumpHexBytes(certId.getIssuerKeyHash(), 256, "", ""));
+                sb.append("\n");
+                sb.append("\tSerial Number: ").append(certId.getSerialNumber());
+                sb.append("\n");
+                sb.append("This Update: ");
+                sb.append(utcDateFmt.format(thisUpdate)).append("\n");
+                if (lsrNextUpdate != null) {
+                    sb.append("Next Update: ");
+                    sb.append(utcDateFmt.format(lsrNextUpdate)).append("\n");
+                }
+
+                if (!singleExtensions.isEmpty()) {
+                    sb.append("Extensions (").append(singleExtensions.size()).
+                            append(")\n");
+                    for (Extension ext : singleExtensions.values()) {
+                        sb.append("\t").append(ext).append("\n");
+                    }
+                }
+
+                return sb.toString();
+            }
+
+            public byte[] getBytes() throws IOException {
+                byte[] nullData = { };
+                DerOutputStream responseSeq = new DerOutputStream();
+                DerOutputStream srStream = new DerOutputStream();
+
+                // Encode the CertId
+                certId.encode(srStream);
+
+                // Next, encode the CertStatus field
+                CertStatus csiType = csInfo.getType();
+                switch (csiType) {
+                    case CERT_STATUS_GOOD:
+                        srStream.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                false, (byte)0), nullData);
+                        break;
+                    case CERT_STATUS_REVOKED:
+                        DerOutputStream revInfo = new DerOutputStream();
+                        revInfo.putGeneralizedTime(csInfo.getRevocationTime());
+                        CRLReason revReason = csInfo.getRevocationReason();
+                        if (revReason != null) {
+                            byte[] revDer = new byte[3];
+                            revDer[0] = DerValue.tag_Enumerated;
+                            revDer[1] = 1;
+                            revDer[2] = (byte)revReason.ordinal();
+                            revInfo.write(DerValue.createTag(
+                                    DerValue.TAG_CONTEXT, true, (byte)0),
+                                    revDer);
+                        }
+                        srStream.write(DerValue.createTag(
+                                DerValue.TAG_CONTEXT, true, (byte)1),
+                                revInfo);
+                        break;
+                    case CERT_STATUS_UNKNOWN:
+                        srStream.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                false, (byte)2), nullData);
+                        break;
+                    default:
+                        throw new IOException("Unknown CertStatus: " + csiType);
+                }
+
+                // Add the necessary dates
+                srStream.putGeneralizedTime(thisUpdate);
+                if (lsrNextUpdate != null) {
+                    DerOutputStream nuStream = new DerOutputStream();
+                    nuStream.putGeneralizedTime(lsrNextUpdate);
+                    srStream.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                            true, (byte)0), nuStream);
+                }
+
+                // TODO add singleResponse Extension support
+
+                // Add the single response to the response output stream
+                responseSeq.write(DerValue.tag_Sequence, srStream);
+                return responseSeq.toByteArray();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ALPN/SSLEngineAlpnTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2003, 2016, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8051498 8145849 8170282
+ * @summary JEP 244: TLS Application-Layer Protocol Negotiation Extension
+ * @compile MyX509ExtendedKeyManager.java
+ *
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   h2          h2
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 UNUSED   h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 UNUSED   h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest h4,h3,h2    UNUSED   h1,h2       h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY       UNUSED   h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest H2          UNUSED   h2          ERROR
+ * @run main/othervm SSLEngineAlpnTest h2          UNUSED   http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       http/1.1,h2 h2
+ * @run main/othervm SSLEngineAlpnTest UNUSED      http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest UNUSED      EMPTY    h2,http/1.1 NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      H2       h2          ERROR
+ * @run main/othervm SSLEngineAlpnTest UNUSED      h2       http/1.1    ERROR
+ *
+ * @run main/othervm SSLEngineAlpnTest h2          h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest H2          h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 http/1.1 h2,http/1.1 http/1.1
+ * @run main/othervm SSLEngineAlpnTest http/1.1,h2 h2       h2,http/1.1 h2
+ * @run main/othervm SSLEngineAlpnTest EMPTY       h2       h2          h2
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 EMPTY    http/1.1    NONE
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 h2       EMPTY       NONE
+ * @run main/othervm SSLEngineAlpnTest UNUSED      UNUSED   http/1.1,h2 NONE
+ * @run main/othervm SSLEngineAlpnTest h2          h2       http/1.1    ERROR
+ * @run main/othervm SSLEngineAlpnTest h2,http/1.1 H2       http/1.1    ERROR
+ */
+/**
+ * A simple SSLEngine-based client/server that demonstrates the proposed API
+ * changes for JEP 244 in support of the TLS ALPN extension (RFC 7301).
+ *
+ * Usage:
+ *     java SSLEngineAlpnTest <server-APs> <callback-AP> <client-APs> <result>
+ *
+ * where:
+ *      EMPTY  indicates that ALPN is disabled
+ *      UNUSED indicates that no ALPN values are supplied (server-side only)
+ *      ERROR  indicates that an exception is expected
+ *      NONE   indicates that no ALPN is expected
+ *
+ * This example is based on our standard SSLEngineTemplate.
+ *
+ * The immediate consumer of ALPN will be HTTP/2 (RFC 7540), aka H2. The H2 IETF
+ * Working Group wanted to use TLSv1.3+ as the secure transport mechanism, but
+ * TLSv1.3 wasn't ready. The H2 folk agreed to a compromise that only TLSv1.2+
+ * can be used, and that if TLSv1.2 was selected, non-TLSv.1.3-approved
+ * ciphersuites would be blacklisted and their use discouraged.
+ *
+ * In order to support connections that might negotiate either HTTP/1.1 and H2,
+ * the guidance from the IETF Working Group is that the H2 ciphersuites be
+ * prioritized/tried first.
+ */
+
+/*
+ * The original SSLEngineTemplate comments follow.
+ *
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+import java.util.Arrays;
+
+public class SSLEngineAlpnTest {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+
+    private static boolean hasServerAPs; // whether server APs are present
+    private static boolean hasCallback; // whether a callback is present
+
+    private final SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    private static final String keyFilename
+            = System.getProperty("test.src", ".") + "/" + pathToStores
+            + "/" + keyStoreFile;
+    private static final String trustFilename
+            = System.getProperty("test.src", ".") + "/" + pathToStores
+            + "/" + trustStoreFile;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+        System.setProperty("jdk.tls.acknowledgeCloseNotify", "true");
+        System.out.println("Test args: " + Arrays.toString(args));
+
+        // Validate parameters
+        if (args.length != 4) {
+            throw new Exception("Invalid number of test parameters");
+        }
+
+        hasServerAPs = !args[0].equals("UNUSED"); // are server APs being used?
+        hasCallback = !args[1].equals("UNUSED"); // is callback being used?
+
+        SSLEngineAlpnTest test = new SSLEngineAlpnTest(args[3]);
+        try {
+            test.runTest(convert(args[0]), args[1], convert(args[2]), args[3]);
+        } catch (SSLHandshakeException she) {
+            if (args[3].equals("ERROR")) {
+                System.out.println("Caught the expected exception: " + she);
+            } else {
+                throw she;
+            }
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLEngineAlpnTest(String expectedAP) throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        KeyManager [] kms = kmf.getKeyManagers();
+        if (!(kms[0] instanceof X509ExtendedKeyManager)) {
+            throw new Exception("kms[0] not X509ExtendedKeyManager");
+        }
+
+        kms = new KeyManager[] { new MyX509ExtendedKeyManager(
+                (X509ExtendedKeyManager) kms[0], expectedAP,
+                !hasCallback && hasServerAPs) };
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kms, tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Convert a comma-separated list into an array of strings.
+     */
+    private static String[] convert(String list) {
+        if (list.equals("UNUSED")) {
+            return null;
+        }
+
+        if (list.equals("EMPTY")) {
+            return new String[0];
+        }
+
+        String[] strings;
+        if (list.indexOf(',') > 0) {
+            strings = list.split(",");
+        } else {
+            strings = new String[]{ list };
+        }
+
+        return strings;
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest(String[] serverAPs, String callbackAP,
+            String[] clientAPs, String expectedAP) throws Exception {
+
+        boolean dataDone = false;
+
+        createSSLEngines(serverAPs, callbackAP, clientAPs);
+        createBuffers();
+
+        SSLEngineResult clientResult;   // results from client's last operation
+        SSLEngineResult serverResult;   // results from server's last operation
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        while (!isEngineClosed(clientEngine)
+                || !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+            checkAPResult(clientEngine, clientResult, expectedAP);
+
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            checkAPResult(serverEngine, serverResult, expectedAP);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("----");
+
+            clientResult = clientEngine.unwrap(sTOc, clientIn);
+            log("client unwrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+            checkAPResult(clientEngine, clientResult, expectedAP);
+
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            log("server unwrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            checkAPResult(serverEngine, serverResult, expectedAP);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position())
+                    && (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                log("\tClosing clientEngine's *OUTBOUND*...");
+                clientEngine.closeOutbound();
+                // serverEngine.closeOutbound();
+                dataDone = true;
+            }
+        }
+    }
+
+    /*
+     * Check that the resulting connection meets our defined ALPN
+     * criteria.  If we were connecting to a non-JSSE implementation,
+     * the server might have negotiated something we shouldn't accept.
+     *
+     * If we were expecting an ALPN value from server, let's make sure
+     * the conditions match.
+     */
+    private static void checkAPResult(SSLEngine engine, SSLEngineResult result,
+            String expectedAP) throws Exception {
+
+        if (result.getHandshakeStatus() != HandshakeStatus.FINISHED) {
+            return;
+        }
+
+        if (engine.getHandshakeApplicationProtocol() != null) {
+            throw new Exception ("getHandshakeApplicationProtocol() should "
+                    + "return null after the handshake is completed");
+        }
+
+        String ap = engine.getApplicationProtocol();
+        System.out.println("Application Protocol: \"" + ap + "\"");
+
+        if (ap == null) {
+            throw new Exception(
+                "Handshake was completed but null was received");
+        }
+        if (expectedAP.equals("NONE")) {
+            if (!ap.isEmpty()) {
+                throw new Exception("Expected no ALPN value");
+            } else {
+                System.out.println("No ALPN value negotiated, as expected");
+            }
+        } else if (!expectedAP.equals(ap)) {
+            throw new Exception(expectedAP +
+                " ALPN value not available on negotiated connection");
+        }
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines(String[] serverAPs, String callbackAP,
+            String[] clientAPs) throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+
+        SSLParameters sslp = serverEngine.getSSLParameters();
+
+        sslp.setNeedClientAuth(true);
+
+        /*
+         * The default ciphersuite ordering from the SSLContext may not
+         * reflect "h2" ciphersuites as being preferred, additionally the
+         * client may not send them in an appropriate order. We could resort
+         * the suite list if so desired.
+         */
+        String[] suites = sslp.getCipherSuites();
+        sslp.setCipherSuites(suites);
+        if (serverAPs != null) {
+            sslp.setApplicationProtocols(serverAPs);
+        }
+        sslp.setUseCipherSuitesOrder(true);  // Set server side order
+
+        serverEngine.setSSLParameters(sslp);
+
+        // check that no callback has been registered
+        if (serverEngine.getHandshakeApplicationProtocolSelector() != null) {
+            throw new Exception("getHandshakeApplicationProtocolSelector() " +
+                "should return null");
+        }
+
+        if (hasCallback) {
+            serverEngine.setHandshakeApplicationProtocolSelector(
+                (sslEngine, clientProtocols) -> {
+                    return callbackAP.equals("EMPTY") ? "" : callbackAP;
+                });
+
+            // check that the callback can be retrieved
+            if (serverEngine.getHandshakeApplicationProtocolSelector()
+                    == null) {
+                throw new Exception("getHandshakeApplicationProtocolSelector()"
+                    + " should return non-null");
+            }
+        }
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+        sslp = clientEngine.getSSLParameters();
+        if (clientAPs != null) {
+            sslp.setApplicationProtocols(clientAPs);
+        }
+        clientEngine.setSSLParameters(sslp);
+
+        if ((clientEngine.getHandshakeApplicationProtocol() != null) ||
+                (serverEngine.getHandshakeApplicationProtocol() != null)) {
+            throw new Exception ("getHandshakeApplicationProtocol() should "
+                    + "return null before the handshake starts");
+        }
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                        "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n"
+                    + "\t\"getStatus() / getHandshakeStatus()\" +\n"
+                    + "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str
+                + result.getStatus() + "/" + hsStatus + ", "
+                + result.bytesConsumed() + "/" + result.bytesProduced()
+                + " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/FixingJavadocs/ComURLNulls.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4387882 4451038
+ * @summary Need to revisit the javadocs for JSSE, especially the
+ *      promoted classes, and HttpsURLConnection.getCipherSuite throws
+ *      NullPointerException
+ * @modules java.base/com.sun.net.ssl
+ *          java.base/com.sun.net.ssl.internal.www.protocol.https
+ * @run main/othervm ComURLNulls
+ *
+ *     SunJSSE does not support dynamic system properties, no way to re-use
+ *     system properties in samevm/agentvm mode.
+ * @author Brad Wetmore
+ */
+
+import java.net.*;
+import java.io.*;
+import javax.net.ssl.*;
+import com.sun.net.ssl.HttpsURLConnection;
+import com.sun.net.ssl.HostnameVerifier;
+
+/*
+ * Tests that the com null argument changes made it in ok.
+ */
+
+public class ComURLNulls {
+
+    private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory {
+        private static String SUPPORTED_PROTOCOL = "https";
+
+        public URLStreamHandler createURLStreamHandler(String protocol) {
+            if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL))
+                return null;
+
+            return new com.sun.net.ssl.internal.www.protocol.https.Handler();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        HostnameVerifier reservedHV =
+            HttpsURLConnection.getDefaultHostnameVerifier();
+        try {
+            URL.setURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory());
+
+            /**
+             * This test does not establish any connection to the specified
+             * URL, hence a dummy URL is used.
+             */
+            URL foobar = new URL("https://example.com/");
+
+            HttpsURLConnection urlc =
+                (HttpsURLConnection) foobar.openConnection();
+
+            try {
+                urlc.getCipherSuite();
+            } catch (IllegalStateException e) {
+                System.out.print("Caught proper exception: ");
+                System.out.println(e.getMessage());
+            }
+
+            try {
+                urlc.getServerCertificates();
+            } catch (IllegalStateException e) {
+                System.out.print("Caught proper exception: ");
+                System.out.println(e.getMessage());
+            }
+
+            try {
+                urlc.setDefaultHostnameVerifier(null);
+            } catch (IllegalArgumentException e) {
+                System.out.print("Caught proper exception: ");
+                System.out.println(e.getMessage());
+            }
+
+            try {
+                urlc.setHostnameVerifier(null);
+            } catch (IllegalArgumentException e) {
+                System.out.print("Caught proper exception: ");
+                System.out.println(e.getMessage());
+            }
+
+            try {
+                urlc.setDefaultSSLSocketFactory(null);
+            } catch (IllegalArgumentException e) {
+                System.out.print("Caught proper exception: ");
+                System.out.println(e.getMessage());
+            }
+
+            try {
+                urlc.setSSLSocketFactory(null);
+            } catch (IllegalArgumentException e) {
+                System.out.print("Caught proper exception");
+                System.out.println(e.getMessage());
+            }
+            System.out.println("TESTS PASSED");
+        } finally {
+            HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/FixingJavadocs/SSLSessionNulls.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2001, 2017, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4387882
+ * @summary Need to revisit the javadocs for JSSE, especially the
+ *      promoted classes.
+ * @library /javax/net/ssl/templates
+ * @modules jdk.crypto.ec
+ * @run main/othervm SSLSessionNulls
+ *
+ *     SunJSSE does not support dynamic system properties, no way to re-use
+ *     system properties in samevm/agentvm mode.
+ * @author Brad Wetmore
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+public class SSLSessionNulls extends SSLSocketTemplate {
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        SSLSession sslSession = socket.getSession();
+
+        try {
+            sslSession.getValue(null);
+        } catch (IllegalArgumentException e) {
+            System.out.print("Caught proper exception: ");
+            System.out.println(e.getMessage());
+        }
+
+        try {
+            sslSession.putValue(null, null);
+        } catch (IllegalArgumentException e) {
+            System.out.print("Caught proper exception: ");
+            System.out.println(e.getMessage());
+        }
+
+        try {
+            sslSession.removeValue(null);
+        } catch (IllegalArgumentException e) {
+            System.out.print("Caught proper exception: ");
+            System.out.println(e.getMessage());
+        }
+
+        String [] names = sslSession.getValueNames();
+        if ((names == null) || (names.length != 0)) {
+            throw new IOException(
+                "getValueNames didn't return 0-length arrary");
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new SSLSessionNulls().run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/Arrays.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2004, 2007, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 5019096
+ * @summary Add scatter/gather APIs for SSLEngine
+ * @run main/othervm Arrays SSL
+ * @run main/othervm Arrays TLS
+ * @run main/othervm Arrays SSLv3
+ * @run main/othervm Arrays TLSv1
+ * @run main/othervm Arrays TLSv1.1
+ * @run main/othervm Arrays TLSv1.2
+ * @run main/othervm Arrays TLSv1.3
+ * @run main/othervm -Djdk.tls.acknowledgeCloseNotify=true Arrays TLSv1.3
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class Arrays {
+
+    private static boolean debug = false;
+    private static boolean acknowledgeCloseNotify =
+        "true".equals(System.getProperty("jdk.tls.acknowledgeCloseNotify"));
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;    // client
+    private SSLEngine ssle2;    // server
+
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer [] appOutArray1;
+    private ByteBuffer [] appInArray1;
+
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine();
+        ssle2.setUseClientMode(false);
+        ssle2.setNeedClientAuth(true);
+    }
+
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) {
+
+            log("================");
+
+            result1 = ssle1.wrap(appOutArray1, oneToTwo);
+            result2 = ssle2.wrap(appOut2, twoToOne);
+
+            log("wrap1:  " + result1);
+            log("oneToTwo  = " + oneToTwo);
+            log("");
+
+            log("wrap2:  " + result2);
+            log("twoToOne  = " + twoToOne);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.flip();
+            twoToOne.flip();
+
+            log("----");
+
+            result1 = ssle1.unwrap(twoToOne, appInArray1);
+            result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+            log("unwrap1: " + result1);
+            log("twoToOne  = " + twoToOne);
+            log("");
+
+            log("unwrap2: " + result2);
+            log("oneToTwo  = " + oneToTwo);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.compact();
+            twoToOne.compact();
+
+            /*
+             * If we've transfered all the data between app1 and app2,
+             * we try to close and see what that gets us.
+             */
+            if (!dataDone) {
+                boolean done = true;
+
+                for (int i = 0; i < appOutArray1.length; i++) {
+                    if (appOutArray1[i].remaining() != 0) {
+                        log("1st out not done");
+                        done = false;
+                    }
+                }
+
+                if (appOut2.remaining() != 0) {
+                    log("2nd out not done");
+                    done = false;
+                }
+
+                if (done) {
+                    log("Closing ssle1's *OUTBOUND*...");
+                    for (int i = 0; i < appOutArray1.length; i++) {
+                        appOutArray1[i].rewind();
+                    }
+                    ssle1.closeOutbound();
+                    String protocol = ssle2.getSession().getProtocol();
+                    if (!acknowledgeCloseNotify) {
+                        switch (ssle2.getSession().getProtocol()) {
+                            case "SSLv3":
+                            case "TLSv1":
+                            case "TLSv1.1":
+                            case "TLSv1.2":
+                                break;
+                            default:    // TLSv1.3
+                                // TLS 1.3, half-close only.
+                                ssle2.closeOutbound();
+                        }
+                    }
+                    dataDone = true;
+                }
+            }
+        }
+        checkTransfer(appOutArray1,  appIn2);
+        appInArray1[appInArray1.length - 1].limit(
+            appInArray1[appInArray1.length - 1].position());
+        checkTransfer(appInArray1, appOut2);
+    }
+
+    private static String contextVersion;
+    public static void main(String args[]) throws Exception {
+        contextVersion = args[0];
+
+        Arrays test;
+
+        test = new Arrays();
+
+        test.createSSLEngines();
+
+        test.runTest();
+
+        System.err.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public Arrays() throws Exception {
+        sslc = getSSLContext(keyFilename, trustFilename);
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext(String keyFile, String trustFile)
+            throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance(contextVersion);
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        ByteBuffer strBB = ByteBuffer.wrap(
+            "Hi Engine2, I'm SSLEngine1, So Be it" .getBytes());
+
+        strBB.position(0);
+        strBB.limit(5);
+        ByteBuffer appOut1a = strBB.slice();
+
+        strBB.position(5);
+        strBB.limit(15);
+        ByteBuffer appOut1b = strBB.slice();
+
+        strBB.position(15);
+        strBB.limit(strBB.capacity());
+        ByteBuffer appOut1c = strBB.slice();
+
+        strBB.rewind();
+
+        appOutArray1 = new ByteBuffer [] { appOut1a, appOut1b, appOut1c };
+
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        ByteBuffer appIn1a = ByteBuffer.allocateDirect(5);
+        ByteBuffer appIn1b = ByteBuffer.allocateDirect(10);
+        ByteBuffer appIn1c = ByteBuffer.allocateDirect(appBufferMax + 50);
+        appInArray1 = new ByteBuffer [] { appIn1a, appIn1b, appIn1c };
+
+        log("AppOut1a = " + appOut1a);
+        log("AppOut1a = " + appOut1b);
+        log("AppOut1a = " + appOut1c);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("running delegated task...");
+                runnable.run();
+            }
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void checkTransfer(ByteBuffer [] a, ByteBuffer b)
+            throws Exception {
+
+        b.flip();
+
+        for (int i = 0; i < a.length; i++) {
+            a[i].rewind();
+
+            b.limit(b.position() + a[i].remaining());
+
+            if (!a[i].equals(b)) {
+                throw new Exception("Data didn't transfer cleanly");
+            }
+
+            b.position(b.limit());
+        }
+
+        log("Data transferred cleanly");
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.err.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/CheckStatus.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,714 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4948079
+ * @summary SSLEngineResult needs updating [none yet]
+ * @ignore the dependent implementation details are changed
+ * @run main/othervm -Djsse.enableCBCProtection=false CheckStatus
+ *
+ * @author Brad Wetmore
+ */
+
+/*
+ * This is a simple hack to test a bunch of conditions and check
+ * their return codes.
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class CheckStatus {
+
+    private static boolean debug = true;
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;    // client
+    private SSLEngine ssle2;    // server
+
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer appOut1;         // write side of ssle1
+    private ByteBuffer appIn1;          // read side of ssle1
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine("server", 2);
+        ssle2.setUseClientMode(false);
+    }
+
+    private boolean isHandshaking(SSLEngine e) {
+        return (e.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING);
+    }
+
+    private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut,
+            SSLEngineResult result,
+            Status status, HandshakeStatus hsStatus,
+            int consumed, int produced)
+            throws Exception {
+
+        if ((status != null) && (result.getStatus() != status)) {
+            throw new Exception("Unexpected Status: need = " + status +
+                " got = " + result.getStatus());
+        }
+
+        if ((hsStatus != null) && (result.getHandshakeStatus() != hsStatus)) {
+            throw new Exception("Unexpected hsStatus: need = " + hsStatus +
+                " got = " + result.getHandshakeStatus());
+        }
+
+        if ((consumed != -1) && (consumed != result.bytesConsumed())) {
+            throw new Exception("Unexpected consumed: need = " + consumed +
+                " got = " + result.bytesConsumed());
+        }
+
+        if ((produced != -1) && (produced != result.bytesProduced())) {
+            throw new Exception("Unexpected produced: need = " + produced +
+                " got = " + result.bytesProduced());
+        }
+
+        if ((consumed != -1) && (bbIn.position() != result.bytesConsumed())) {
+            throw new Exception("Consumed " + bbIn.position() +
+                " != " + consumed);
+        }
+
+        if ((produced != -1) && (bbOut.position() != result.bytesProduced())) {
+            throw new Exception("produced " + bbOut.position() +
+                " != " + produced);
+        }
+    }
+
+    private void test() throws Exception {
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        String [] suite1 = new String [] {
+            "SSL_RSA_WITH_RC4_128_MD5" };
+        String [] suite2 = new String [] {
+            "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA" };
+
+        ssle1.setEnabledCipherSuites(suite1);
+        ssle2.setEnabledCipherSuites(suite1);
+
+        log("================");
+
+        log("unexpected empty unwrap");
+        twoToOne.limit(0);
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, 0);
+        twoToOne.limit(twoToOne.capacity());
+
+        log("======================================");
+        log("client hello");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0);
+        runDelegatedTasks(ssle2);
+
+        oneToTwo.compact();
+
+        log("Check for unwrap when wrap needed");
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result2,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, 0);
+
+        log("======================================");
+        log("ServerHello");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_TASK, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        runDelegatedTasks(ssle1);
+
+        log("======================================");
+        log("Key Exchange");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0);
+        runDelegatedTasks(ssle2);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("CCS");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_UNWRAP,
+             result1.bytesProduced(), 0);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("Finished");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_WRAP, result1.bytesProduced(), 0);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("CCS");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        log("======================================");
+        log("FINISHED");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.FINISHED, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.FINISHED, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        log("======================================");
+        log("Check Session/Ciphers");
+
+        String suite = ssle1.getSession().getCipherSuite();
+        if (!suite.equals(suite1[0])) {
+            throw new Exception("suites not equal: " + suite + "/" +
+                suite1[0]);
+        }
+
+        suite = ssle2.getSession().getCipherSuite();
+        if (!suite.equals(suite1[0])) {
+            throw new Exception("suites not equal: " + suite + "/" +
+                suite1[0]);
+        }
+
+        log("======================================");
+        log("DATA");
+
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            appOut1.capacity(), -1);
+        oneToTwo.flip();
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            appOut2.capacity(), -1);
+        twoToOne.flip();
+
+        SSLEngineResult result3 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result3,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            result2.bytesProduced(), result2.bytesConsumed());
+        twoToOne.compact();
+
+        SSLEngineResult result4 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result4,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            result1.bytesProduced(), result1.bytesConsumed());
+        oneToTwo.compact();
+
+        appIn1.clear();
+        appIn2.clear();
+        appOut1.rewind();
+        appOut2.rewind();
+
+        log("======================================");
+        log("RENEGOTIATE");
+
+        ssle2.getSession().invalidate();
+        ssle2.setNeedClientAuth(true);
+
+        ssle1.setEnabledCipherSuites(suite2);
+        ssle2.setEnabledCipherSuites(suite2);
+
+        ssle2.beginHandshake();
+
+        log("======================================");
+        log("HelloRequest");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_TASK, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        runDelegatedTasks(ssle1);
+
+        log("======================================");
+        log("ClientHello");
+
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0);
+        runDelegatedTasks(ssle2);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("CLIENT->SERVER DATA IN MIDDLE OF HANDSHAKE");
+
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NEED_UNWRAP,
+            appOut1.capacity(), -1);
+        oneToTwo.flip();
+
+        result4 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result4,
+            Status.OK, HandshakeStatus.NEED_WRAP,
+            result1.bytesProduced(), result1.bytesConsumed());
+        oneToTwo.compact();
+
+        appIn2.clear();
+        appOut1.rewind();
+
+        log("======================================");
+        log("ServerHello");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_TASK, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        runDelegatedTasks(ssle1);
+
+        log("======================================");
+        log("SERVER->CLIENT DATA IN MIDDLE OF HANDSHAKE");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_UNWRAP,
+            appOut2.capacity(), -1);
+        twoToOne.flip();
+
+        result3 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result3,
+            Status.OK, HandshakeStatus.NEED_WRAP,
+            result2.bytesProduced(), result2.bytesConsumed());
+        twoToOne.compact();
+
+        appIn1.clear();
+        appOut2.rewind();
+
+        log("======================================");
+        log("Client Cert and Key Exchange");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0);
+        runDelegatedTasks(ssle2);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("CCS");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_UNWRAP,
+             result1.bytesProduced(), 0);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("Finished");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+
+        oneToTwo.flip();
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.OK, HandshakeStatus.NEED_WRAP, result1.bytesProduced(), 0);
+
+        oneToTwo.compact();
+
+        log("======================================");
+        log("CCS");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        log("======================================");
+        log("FINISHED");
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.FINISHED, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.FINISHED, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        log("======================================");
+        log("Check Session/Ciphers");
+
+        suite = ssle1.getSession().getCipherSuite();
+        if (!suite.equals(suite2[0])) {
+            throw new Exception("suites not equal: " + suite + "/" +
+                suite2[0]);
+        }
+
+        suite = ssle2.getSession().getCipherSuite();
+        if (!suite.equals(suite2[0])) {
+            throw new Exception("suites not equal: " + suite + "/" +
+                suite2[0]);
+        }
+
+        log("======================================");
+        log("DATA USING NEW SESSION");
+
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            appOut1.capacity(), -1);
+        oneToTwo.flip();
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            appOut2.capacity(), -1);
+        twoToOne.flip();
+
+        result3 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result3,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            result2.bytesProduced(), result2.bytesConsumed());
+        twoToOne.compact();
+
+        result4 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result4,
+            Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            result1.bytesProduced(), result1.bytesConsumed());
+        oneToTwo.compact();
+
+        appIn1.clear();
+        appIn2.clear();
+        appOut1.rewind();
+        appOut2.rewind();
+
+        log("======================================");
+        log("CN");
+
+        if (isHandshaking(ssle1)) {
+            throw new Exception("ssle1 IS handshaking");
+        }
+
+        if (isHandshaking(ssle2)) {
+            throw new Exception("ssle2 IS handshaking");
+        }
+
+        ssle2.closeOutbound();
+
+        if (!isHandshaking(ssle2)) {
+            throw new Exception("ssle1 IS NOT handshaking");
+        }
+
+        appOut1.rewind();
+        appOut2.rewind();
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.CLOSED, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        twoToOne.flip();
+
+        if (ssle1.isInboundDone()) {
+            throw new Exception("ssle1 inboundDone");
+        }
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.CLOSED, HandshakeStatus.NEED_WRAP,
+            result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        if (!ssle1.isInboundDone()) {
+            throw new Exception("ssle1 inboundDone");
+        }
+
+        if (!isHandshaking(ssle1)) {
+            throw new Exception("ssle1 IS NOT handshaking");
+        }
+
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.CLOSED, HandshakeStatus.NEED_UNWRAP, 0, 0);
+        twoToOne.flip();
+
+        log("======================================");
+        log("CN response");
+
+        if (ssle1.isOutboundDone()) {
+            throw new Exception("ssle1 outboundDone");
+        }
+
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+             Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING, 0, -1);
+
+        if (!ssle1.isOutboundDone()) {
+            throw new Exception("ssle1 outboundDone is NOT done");
+        }
+
+        if (isHandshaking(ssle1)) {
+            throw new Exception("ssle1 IS handshaking");
+        }
+
+        oneToTwo.flip();
+
+        if (!ssle2.isOutboundDone()) {
+            throw new Exception("ssle1 outboundDone");
+        }
+
+        if (ssle2.isInboundDone()) {
+            throw new Exception("ssle1 inboundDone");
+        }
+
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+        checkResult(oneToTwo, appIn2, result2,
+             Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+             result1.bytesProduced(), 0);
+
+        if (!ssle2.isOutboundDone()) {
+            throw new Exception("ssle1 outboundDone is NOT done");
+        }
+
+        if (!ssle2.isInboundDone()) {
+            throw new Exception("ssle1 inboundDone is NOT done");
+        }
+
+        if (isHandshaking(ssle2)) {
+            throw new Exception("ssle1 IS handshaking");
+        }
+
+        oneToTwo.compact();
+    }
+
+    public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        CheckStatus cs;
+
+        cs = new CheckStatus();
+
+        cs.createSSLEngines();
+
+        cs.test();
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public CheckStatus() throws Exception {
+        sslc = getSSLContext(keyFilename, trustFilename);
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext(String keyFile, String trustFile)
+            throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        log("AppOut1 = " + appOut1);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngine engine) throws Exception {
+
+        Runnable runnable;
+        while ((runnable = engine.getDelegatedTask()) != null) {
+            log("running delegated task...");
+            runnable.run();
+        }
+    }
+
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("Data transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/ConnectionTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,685 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4495742
+ * @summary Add non-blocking SSL/TLS functionality, usable with any
+ *      I/O abstraction
+ * @ignore the dependent implementation details are changed
+ * @author Brad Wetmore
+ *
+ * @run main/othervm ConnectionTest
+ */
+
+/*
+ * This is a bit hacky, meant to test various conditions.  The main
+ * thing I wanted to do with this was to do buffer reads/writes
+ * when buffers were not empty.  (buffer.position() = 10)
+ * The code could certainly be tightened up a lot.
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class ConnectionTest {
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;
+    private SSLEngine ssle2;
+
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer appIn1, appOut1;
+    private ByteBuffer appIn2, appOut2;
+    private ByteBuffer oneToTwo, twoToOne;
+    private ByteBuffer emptyBuffer;
+
+    private ByteBuffer  oneToTwoShifter, twoToOneShifter;
+
+    private String hostname = "hostname";
+    private int portNumber = 77;
+
+    public ConnectionTest()
+            throws Exception {
+
+        sslc = getSSLContext();
+        ssle1 = sslc.createSSLEngine(hostname, portNumber);
+        ssle2 = sslc.createSSLEngine();
+
+        ssle1.setEnabledCipherSuites(new String [] {
+            "SSL_RSA_WITH_RC4_128_MD5"});
+
+        ssle2.setEnabledCipherSuites(new String [] {
+            "SSL_RSA_WITH_RC4_128_MD5"});
+
+        createBuffers();
+    }
+
+    private SSLContext getSSLContext() throws Exception {
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 10);
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 10);
+
+        appIn1.position(10);
+        appIn2.position(10);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax + 10);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax + 10);
+
+        oneToTwo.position(10);
+        twoToOne.position(10);
+        oneToTwoShifter = oneToTwo.slice();
+        twoToOneShifter = twoToOne.slice();
+
+        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        emptyBuffer = ByteBuffer.allocate(10);
+        emptyBuffer.limit(5);
+        emptyBuffer.position(emptyBuffer.limit());
+
+        System.out.println("AppOut1 = " + appOut1);
+        System.out.println("AppOut2 = " + appOut2);
+        System.out.println();
+    }
+
+    private void checkResult(SSLEngineResult result, Status status,
+            HandshakeStatus hsStatus, int consumed, int produced,
+            boolean done) throws Exception {
+
+        if ((status != null) && (result.getStatus() != status)) {
+            throw new Exception("Unexpected Status: need = " + status +
+                " got = " + result.getStatus());
+        }
+
+        if ((hsStatus != null) && (result.getHandshakeStatus() != hsStatus)) {
+            throw new Exception("Unexpected hsStatus: need = " + hsStatus +
+                " got = " + result.getHandshakeStatus());
+        }
+
+        if ((consumed != -1) && (consumed != result.bytesConsumed())) {
+            throw new Exception("Unexpected consumed: need = " + consumed +
+                " got = " + result.bytesConsumed());
+        }
+
+        if ((produced != -1) && (produced != result.bytesProduced())) {
+            throw new Exception("Unexpected produced: need = " + produced +
+                " got = " + result.bytesProduced());
+        }
+
+        if (done && (hsStatus == HandshakeStatus.FINISHED)) {
+            throw new Exception(
+                "Handshake already reported finished");
+        }
+
+    }
+
+    private boolean isHandshaking(SSLEngine e) {
+        return (e.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING);
+    }
+
+    private void test() throws Exception {
+        ssle1.setUseClientMode(true);
+        ssle2.setUseClientMode(false);
+        ssle2.setNeedClientAuth(true);
+
+        System.out.println("Testing for early unwrap/wrap");
+        SSLEngineResult result1 = ssle1.unwrap(twoToOne, appIn1);
+        SSLEngineResult result2 = ssle2.wrap(appOut2, oneToTwo);
+
+        /*
+         * These should not consume/produce data, because they
+         * are client and server, respectively, and don't
+         * start handshaking this way.
+         */
+        checkResult(result1, Status.OK, HandshakeStatus.NEED_WRAP,
+            0, 0, false);
+        checkResult(result2, Status.OK, HandshakeStatus.NEED_UNWRAP,
+            0, 0, false);
+
+        System.out.println("Doing Initial Handshake");
+
+        boolean done1 = false;
+        boolean done2 = false;
+
+        /*
+         * Do initial handshaking
+         */
+        while (isHandshaking(ssle1) ||
+                isHandshaking(ssle2)) {
+
+            System.out.println("================");
+
+            result1 = ssle1.wrap(emptyBuffer, oneToTwo);
+            checkResult(result1, null, null, 0, -1, done1);
+            result2 = ssle2.wrap(emptyBuffer, twoToOne);
+            checkResult(result2, null, null, 0, -1, done2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done1 = true;
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done2 = true;
+            }
+
+            System.out.println("wrap1 = " + result1);
+            System.out.println("wrap2 = " + result2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle1.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle2.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            oneToTwo.flip();
+            twoToOne.flip();
+
+            oneToTwo.position(10);
+            twoToOne.position(10);
+
+            System.out.println("----");
+
+            result1 = ssle1.unwrap(twoToOne, appIn1);
+            checkResult(result1, null, null, -1, 0, done1);
+            result2 = ssle2.unwrap(oneToTwo, appIn2);
+            checkResult(result2, null, null, -1, 0, done2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done1 = true;
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done2 = true;
+            }
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle1.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle2.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            System.out.println("unwrap1 = " + result1);
+            System.out.println("unwrap2 = " + result2);
+
+            oneToTwoShifter.position(oneToTwo.position() - 10);
+            oneToTwoShifter.limit(oneToTwo.limit() - 10);
+            twoToOneShifter.position(twoToOne.position() - 10);
+            twoToOneShifter.limit(twoToOne.limit() - 10);
+            oneToTwoShifter.compact();
+            twoToOneShifter.compact();
+            oneToTwo.position(oneToTwoShifter.position() + 10);
+            oneToTwo.limit(oneToTwoShifter.limit() + 10);
+            twoToOne.position(twoToOneShifter.position() + 10);
+            twoToOne.limit(twoToOneShifter.limit() + 10);
+        }
+
+        System.out.println("\nDONE HANDSHAKING");
+        System.out.println("================");
+
+        if (!done1 || !done2) {
+            throw new Exception("Both should be true:\n" +
+                " done1 = " + done1 + " done2 = " + done2);
+        }
+
+        String host = ssle1.getPeerHost();
+        int port = ssle1.getPeerPort();
+        if (!host.equals(hostname) || (port != portNumber)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        host = ssle2.getPeerHost();
+        port = ssle2.getPeerPort();
+        if ((host != null) || (port != -1)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        SSLSession ssls1 = ssle1.getSession();
+
+        host = ssls1.getPeerHost();
+        port = ssls1.getPeerPort();
+        if (!host.equals(hostname) || (port != portNumber)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        SSLSession ssls2 = ssle2.getSession();
+
+        host = ssls2.getPeerHost();
+        port = ssls2.getPeerPort();
+        if ((host != null) || (port != -1)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        /*
+         * Should be able to write/read a small buffer like this.
+         */
+        int appOut1Len = appOut1.remaining();
+        int appOut2Len = appOut2.remaining();
+        int net1Len;
+        int net2Len;
+
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(result1, Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            appOut1Len, -1, false);
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(result2, Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            appOut2Len, -1, false);
+        net1Len = result1.bytesProduced();
+        net2Len = result2.bytesProduced();
+
+        System.out.println("wrap1 = " + result1);
+        System.out.println("wrap2 = " + result2);
+
+        oneToTwo.flip();
+        twoToOne.flip();
+
+        oneToTwo.position(10);
+        twoToOne.position(10);
+
+        System.out.println("----");
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(result1, Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            net2Len, appOut2Len, false);
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(result2, Status.OK, HandshakeStatus.NOT_HANDSHAKING,
+            net1Len, appOut1Len, false);
+
+        System.out.println("unwrap1 = " + result1);
+        System.out.println("unwrap2 = " + result2);
+
+        oneToTwoShifter.position(oneToTwo.position() - 10);
+        oneToTwoShifter.limit(oneToTwo.limit() - 10);
+        twoToOneShifter.position(twoToOne.position() - 10);
+        twoToOneShifter.limit(twoToOne.limit() - 10);
+        oneToTwoShifter.compact();
+        twoToOneShifter.compact();
+        oneToTwo.position(oneToTwoShifter.position() + 10);
+        oneToTwo.limit(oneToTwoShifter.limit() + 10);
+        twoToOne.position(twoToOneShifter.position() + 10);
+        twoToOne.limit(twoToOneShifter.limit() + 10);
+
+        ssls2.invalidate();
+        ssle2.beginHandshake();
+
+        System.out.println("\nRENEGOTIATING");
+        System.out.println("=============");
+
+        done1 = false;
+        done2 = false;
+
+        appIn1.clear();
+        appIn2.clear();
+
+        /*
+         * Do a quick test to see if this can do a switch
+         * into client mode, at this point, you shouldn't be able
+         * to switch back.
+         */
+        try {
+            System.out.println("Try to change client mode");
+            ssle2.setUseClientMode(true);
+            throw new Exception("Should have thrown IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+            System.out.println("Caught correct IllegalArgumentException");
+        }
+
+        while (isHandshaking(ssle1) ||
+                isHandshaking(ssle2)) {
+
+            System.out.println("================");
+
+            result1 = ssle1.wrap(emptyBuffer, oneToTwo);
+            checkResult(result1, null, null, 0, -1, done1);
+            result2 = ssle2.wrap(emptyBuffer, twoToOne);
+            checkResult(result2, null, null, 0, -1, done2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done1 = true;
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done2 = true;
+            }
+
+            System.out.println("wrap1 = " + result1);
+            System.out.println("wrap2 = " + result2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle1.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle2.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            oneToTwo.flip();
+            twoToOne.flip();
+
+            oneToTwo.position(10);
+            twoToOne.position(10);
+
+            System.out.println("----");
+
+            result1 = ssle1.unwrap(twoToOne, appIn1);
+            checkResult(result1, null, null, -1, 0, done1);
+            result2 = ssle2.unwrap(oneToTwo, appIn2);
+            checkResult(result2, null, null, -1, 0, done2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done1 = true;
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.FINISHED) {
+                done2 = true;
+            }
+
+            System.out.println("unwrap1 = " + result1);
+            System.out.println("unwrap2 = " + result2);
+
+            if (result1.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle1.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            if (result2.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable runnable;
+                while ((runnable = ssle2.getDelegatedTask()) != null) {
+                    runnable.run();
+                }
+            }
+
+            oneToTwoShifter.position(oneToTwo.position() - 10);
+            oneToTwoShifter.limit(oneToTwo.limit() - 10);
+            twoToOneShifter.position(twoToOne.position() - 10);
+            twoToOneShifter.limit(twoToOne.limit() - 10);
+            oneToTwoShifter.compact();
+            twoToOneShifter.compact();
+            oneToTwo.position(oneToTwoShifter.position() + 10);
+            oneToTwo.limit(oneToTwoShifter.limit() + 10);
+            twoToOne.position(twoToOneShifter.position() + 10);
+            twoToOne.limit(twoToOneShifter.limit() + 10);
+        }
+
+        host = ssle1.getPeerHost();
+        port = ssle1.getPeerPort();
+        if (!host.equals(hostname) || (port != portNumber)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        host = ssle2.getPeerHost();
+        port = ssle2.getPeerPort();
+        if ((host != null) || (port != -1)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        SSLSession ssls3 = ssle2.getSession();
+
+        host = ssls1.getPeerHost();
+        port = ssls1.getPeerPort();
+        if (!host.equals(hostname) || (port != portNumber)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        SSLSession ssls4 = ssle2.getSession();
+
+        host = ssls2.getPeerHost();
+        port = ssls2.getPeerPort();
+        if ((host != null) || (port != -1)) {
+            throw new Exception("unexpected host/port " + host + ":" + port);
+        }
+
+        System.out.println("\nDoing close");
+        System.out.println("===========");
+
+        ssle1.closeOutbound();
+        ssle2.closeOutbound();
+
+        oneToTwo.flip();
+        twoToOne.flip();
+        oneToTwo.position(10);
+        twoToOne.position(10);
+
+        appIn1.clear();
+        appIn2.clear();
+
+        System.out.println("LAST UNWRAP");
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(result1, Status.BUFFER_UNDERFLOW,
+            HandshakeStatus.NEED_WRAP, 0, 0, false);
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(result2, Status.BUFFER_UNDERFLOW,
+            HandshakeStatus.NEED_WRAP, 0, 0, false);
+
+        System.out.println("unwrap1 = " + result1);
+        System.out.println("unwrap2 = " + result2);
+
+        oneToTwoShifter.position(oneToTwo.position() - 10);
+        oneToTwoShifter.limit(oneToTwo.limit() - 10);
+        twoToOneShifter.position(twoToOne.position() - 10);
+        twoToOneShifter.limit(twoToOne.limit() - 10);
+        oneToTwoShifter.compact();
+        twoToOneShifter.compact();
+        oneToTwo.position(oneToTwoShifter.position() + 10);
+        oneToTwo.limit(oneToTwoShifter.limit() + 10);
+        twoToOne.position(twoToOneShifter.position() + 10);
+        twoToOne.limit(twoToOneShifter.limit() + 10);
+
+        System.out.println("LAST WRAP");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(result1, Status.CLOSED, HandshakeStatus.NEED_UNWRAP,
+            0, -1, false);
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(result2, Status.CLOSED, HandshakeStatus.NEED_UNWRAP,
+            0, -1, false);
+
+        System.out.println("wrap1 = " + result1);
+        System.out.println("wrap2 = " + result2);
+
+        net1Len = result1.bytesProduced();
+        net2Len = result2.bytesProduced();
+
+        oneToTwo.flip();
+        twoToOne.flip();
+
+        oneToTwo.position(10);
+        twoToOne.position(10);
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(result1, Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+            net1Len, 0, false);
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(result2, Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+            net2Len, 0, false);
+
+        System.out.println("unwrap1 = " + result1);
+        System.out.println("unwrap2 = " + result2);
+
+        oneToTwoShifter.position(oneToTwo.position() - 10);
+        oneToTwoShifter.limit(oneToTwo.limit() - 10);
+        twoToOneShifter.position(twoToOne.position() - 10);
+        twoToOneShifter.limit(twoToOne.limit() - 10);
+        oneToTwoShifter.compact();
+        twoToOneShifter.compact();
+        oneToTwo.position(oneToTwoShifter.position() + 10);
+        oneToTwo.limit(oneToTwoShifter.limit() + 10);
+        twoToOne.position(twoToOneShifter.position() + 10);
+        twoToOne.limit(twoToOneShifter.limit() + 10);
+
+        System.out.println("EXTRA WRAP");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(result1, Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+            0, 0, false);
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(result2, Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+            0, 0, false);
+
+        System.out.println("wrap1 = " + result1);
+        System.out.println("wrap2 = " + result2);
+
+        oneToTwo.flip();
+        twoToOne.flip();
+        oneToTwo.position(10);
+        twoToOne.position(10);
+
+        System.out.println("EXTRA UNWRAP");
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(result1, Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+            0, 0, false);
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(result2, Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING,
+            0, 0, false);
+
+        System.out.println("unwrap1 = " + result1);
+        System.out.println("unwrap2 = " + result2);
+
+        checkSession(ssls1, ssls2, ssls3, ssls4);
+        System.out.println(ssle1);
+        System.out.println(ssle2);
+    }
+
+    private static void checkSession(SSLSession ssls1, SSLSession ssls2,
+            SSLSession ssls3, SSLSession ssls4) throws Exception {
+        System.out.println("\nSession Info for SSLEngine1");
+        System.out.println(ssls1);
+        System.out.println(ssls1.getCreationTime());
+        String peer1 = ssls1.getPeerHost();
+        System.out.println(peer1);
+        String protocol1 = ssls1.getProtocol();
+        System.out.println(protocol1);
+        java.security.cert.Certificate cert1 = ssls1.getPeerCertificates()[0];
+        System.out.println(cert1);
+        String ciphersuite1 = ssls1.getCipherSuite();
+        System.out.println(ciphersuite1);
+        System.out.println();
+
+        System.out.println("\nSession Info for SSLEngine2");
+        System.out.println(ssls2);
+        System.out.println(ssls2.getCreationTime());
+        String peer2 = ssls2.getPeerHost();
+        System.out.println(peer2);
+        String protocol2 = ssls2.getProtocol();
+        System.out.println(protocol2);
+        java.security.cert.Certificate cert2 = ssls2.getPeerCertificates()[0];
+        System.out.println(cert2);
+        String ciphersuite2 = ssls2.getCipherSuite();
+        System.out.println(ciphersuite2);
+        System.out.println();
+
+        if (peer1.equals(peer2)) {
+            throw new Exception("peer hostnames not equal");
+        }
+
+        if (!protocol1.equals(protocol2)) {
+            throw new Exception("protocols not equal");
+        }
+
+        if (!cert1.equals(cert2)) {
+            throw new Exception("certs not equal");
+        }
+
+        if (!ciphersuite1.equals(ciphersuite2)) {
+            throw new Exception("ciphersuites not equal");
+        }
+
+        System.out.println("\nSession Info for SSLEngine3");
+        System.out.println(ssls3);
+        System.out.println("\nSession Info for SSLEngine4");
+        System.out.println(ssls4);
+
+        if (ssls3.equals(ssls1) || ssls4.equals(ssls2)) {
+            throw new Exception("sessions should not be equals");
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        ConnectionTest ct = new ConnectionTest();
+        ct.test();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/EngineCloseOnAlert.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2004, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8133632
+ * @summary javax.net.ssl.SSLEngine does not properly handle received
+ *      SSL fatal alerts
+ * @ignore the dependent implementation details are changed
+ * @run main/othervm EngineCloseOnAlert
+ */
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import javax.net.ssl.*;
+import java.nio.ByteBuffer;
+import java.util.*;
+import java.security.*;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
+
+public class EngineCloseOnAlert {
+
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private static KeyManagerFactory KMF;
+    private static TrustManagerFactory TMF;
+    private static TrustManagerFactory EMPTY_TMF;
+
+    private static final String[] TLS10ONLY = { "TLSv1" };
+    private static final String[] TLS12ONLY = { "TLSv1.2" };
+    private static final String[] ONECIPHER =
+            { "TLS_RSA_WITH_AES_128_CBC_SHA" };
+
+    public interface TestCase {
+        public void runTest() throws Exception;
+    }
+
+    public static void main(String[] args) throws Exception {
+        int failed = 0;
+        List<TestCase> testMatrix = new LinkedList<TestCase>() {{
+            add(clientReceivesAlert);
+            add(serverReceivesAlert);
+        }};
+
+        // Create the various key/trust manager factories we'll need
+        createManagerFactories();
+
+        for (TestCase test : testMatrix) {
+            try {
+                test.runTest();
+            } catch (Exception e) {
+                System.out.println("Exception in test:\n" + e);
+                e.printStackTrace(System.out);
+                failed++;
+            }
+        }
+
+        System.out.println("Total tests: " + testMatrix.size() + ", passed: " +
+                (testMatrix.size() - failed) + ", failed: " + failed);
+        if (failed > 0) {
+            throw new RuntimeException("One or more tests failed.");
+        }
+    }
+
+    private static final TestCase clientReceivesAlert = new TestCase() {
+        @Override
+        public void runTest() throws Exception {
+            System.out.println("");
+            System.out.println("=======================================");
+            System.out.println("Test: Client receives alert from server");
+            System.out.println("=======================================");
+
+            // For this test, we won't initialize any keystore so the
+            // server will throw an exception because it has no key/cert to
+            // match the requested ciphers offered by the client.  This
+            // will generate an alert from the server to the client.
+
+            SSLContext context = SSLContext.getDefault();
+            SSLEngine client = context.createSSLEngine();
+            SSLEngine server = context.createSSLEngine();
+            client.setUseClientMode(true);
+            server.setUseClientMode(false);
+            SSLEngineResult clientResult;
+            SSLEngineResult serverResult;
+
+            ByteBuffer raw = ByteBuffer.allocate(32768);
+            ByteBuffer plain = ByteBuffer.allocate(32768);
+
+            // Generate the client hello and have the server unwrap it
+            client.wrap(plain, raw);
+            checkEngineState(client, NEED_UNWRAP, false, false);
+            raw.flip();
+            System.out.println("Client-to-Server:\n-----------------\n" +
+                    dumpHexBytes(raw, 16, "\n", ":"));
+
+
+            // The server should need to run a delegated task while processing
+            // the client hello data.
+            serverResult = server.unwrap(raw, plain);
+            checkEngineState(server, NEED_TASK, false, false);
+            System.out.println("Server result: " + serverResult);
+            runDelegatedTasks(serverResult, server);
+            checkEngineState(server, NEED_WRAP, true, false);
+
+            try {
+                raw.clear();
+                serverResult = server.wrap(plain, raw);
+                System.out.println("Server result: " + serverResult);
+                runDelegatedTasks(serverResult, server);
+            } catch (SSLException e) {
+                // This is the expected code path
+                System.out.println("Server throws exception: " + e);
+                System.out.println("Server engine state: " +
+                        "isInboundDone = "+ server.isInboundDone() +
+                        ", isOutboundDone = " + server.isOutboundDone() +
+                        ", handshake status = " + server.getHandshakeStatus());
+                checkEngineState(server, NEED_WRAP, true, false);
+            }
+            raw.clear();
+
+            // The above should show that isInboundDone returns true, and
+            // handshake status is NEED_WRAP. That is the correct behavior,
+            // wrap will put a fatal alert message in the buffer.
+            serverResult = server.wrap(plain, raw);
+            System.out.println("Server result (wrap after exception): " +
+                    serverResult);
+            System.out.println("Server engine closure state: isInboundDone="
+                    + server.isInboundDone() + ", isOutboundDone="
+                    + server.isOutboundDone());
+            checkEngineState(server, NEED_UNWRAP, true, true);
+            raw.flip();
+
+            System.out.println("Server-to-Client:\n-----------------\n" +
+                    dumpHexBytes(raw, 16, "\n", ":"));
+
+            // Client side will read the fatal alert and throw exception.
+            try {
+                clientResult = client.unwrap(raw, plain);
+                System.out.println("Client result (unwrap alert): " +
+                    clientResult);
+            } catch (SSLException e) {
+                System.out.println("Client throws exception: " + e);
+                System.out.println("Engine closure status: isInboundDone="
+                        + client.isInboundDone() + ", isOutboundDone="
+                        + client.isOutboundDone() + ", handshake status="
+                        + client.getHandshakeStatus());
+                checkEngineState(client, NOT_HANDSHAKING, true, true);
+            }
+            raw.clear();
+
+            // Last test, we try to unwrap
+            clientResult = client.unwrap(raw, plain);
+            checkEngineState(client, NOT_HANDSHAKING, true, true);
+            System.out.println("Client result (wrap after exception): " +
+                    clientResult);
+        }
+    };
+
+    private static final TestCase serverReceivesAlert = new TestCase() {
+        @Override
+        public void runTest() throws Exception {
+            SSLContext cliContext = SSLContext.getDefault();
+            SSLContext servContext = SSLContext.getInstance("TLS");
+            servContext.init(KMF.getKeyManagers(), TMF.getTrustManagers(),
+                    null);
+            SSLEngine client = cliContext.createSSLEngine();
+            SSLEngine server = servContext.createSSLEngine();
+            client.setUseClientMode(true);
+            client.setEnabledProtocols(TLS12ONLY);
+            client.setEnabledCipherSuites(ONECIPHER);
+            server.setUseClientMode(false);
+            server.setEnabledProtocols(TLS10ONLY);
+            SSLEngineResult clientResult;
+            SSLEngineResult serverResult;
+            ByteBuffer raw = ByteBuffer.allocate(32768);
+            ByteBuffer plain = ByteBuffer.allocate(32768);
+
+            System.out.println("");
+            System.out.println("=======================================");
+            System.out.println("Test: Server receives alert from client");
+            System.out.println("=======================================");
+
+            // Generate the client hello and have the server unwrap it
+            checkEngineState(client, NOT_HANDSHAKING, false, false);
+            client.wrap(plain, raw);
+            checkEngineState(client, NEED_UNWRAP, false, false);
+            raw.flip();
+            System.out.println("Client-to-Server:\n-----------------\n" +
+                    dumpHexBytes(raw, 16, "\n", ":"));
+
+            // The server should need to run a delegated task while processing
+            // the client hello data.
+            serverResult = server.unwrap(raw, plain);
+            checkEngineState(server, NEED_TASK, false, false);
+            runDelegatedTasks(serverResult, server);
+            checkEngineState(server, NEED_WRAP, false, false);
+            raw.compact();
+
+            // The server should now wrap the response back to the client
+            server.wrap(plain, raw);
+            checkEngineState(server, NEED_UNWRAP, false, false);
+            raw.flip();
+            System.out.println("Server-to-Client:\n-----------------\n" +
+                    dumpHexBytes(raw, 16, "\n", ":"));
+
+            // The client should parse this and throw an exception because
+            // It is unwiling to do TLS 1.0
+            clientResult = client.unwrap(raw, plain);
+            checkEngineState(client, NEED_TASK, false, false);
+            runDelegatedTasks(clientResult, client);
+            checkEngineState(client, NEED_UNWRAP, false, false);
+
+            try {
+                client.unwrap(raw, plain);
+            } catch (SSLException e) {
+                System.out.println("Client throws exception: " + e);
+                System.out.println("Engine closure status: isInboundDone="
+                        + client.isInboundDone() + ", isOutboundDone="
+                        + client.isOutboundDone() + ", handshake status="
+                        + client.getHandshakeStatus());
+                checkEngineState(client, NEED_WRAP, true, false);
+            }
+            raw.clear();
+
+            // Now the client should wrap the exception
+            client.wrap(plain, raw);
+            checkEngineState(client, NEED_UNWRAP, true, true);
+            raw.flip();
+            System.out.println("Client-to-Server:\n-----------------\n" +
+                    dumpHexBytes(raw, 16, "\n", ":"));
+
+            try {
+                server.unwrap(raw, plain);
+                checkEngineState(server, NEED_UNWRAP, false, false);
+            } catch (SSLException e) {
+                System.out.println("Server throws exception: " + e);
+                System.out.println("Engine closure status: isInboundDone="
+                        + server.isInboundDone() + ", isOutboundDone="
+                        + server.isOutboundDone() + ", handshake status="
+                        + server.getHandshakeStatus());
+                checkEngineState(server, NOT_HANDSHAKING, true, true);
+            }
+            raw.clear();
+        }
+    };
+
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() ==
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                System.out.println("\trunning delegated task...");
+                runnable.run();
+            }
+            SSLEngineResult.HandshakeStatus hsStatus =
+                    engine.getHandshakeStatus();
+            if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            System.out.println("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    /**
+     *
+     * @param data The array of bytes to dump to stdout.
+     * @param itemsPerLine The number of bytes to display per line
+     * if the {@code lineDelim} character is blank then all bytes will be
+     * printed on a single line.
+     * @param lineDelim The delimiter between lines
+     * @param itemDelim The delimiter between bytes
+     *
+     * @return The hexdump of the byte array
+     */
+    private static String dumpHexBytes(ByteBuffer data, int itemsPerLine,
+            String lineDelim, String itemDelim) {
+        StringBuilder sb = new StringBuilder();
+
+        if (data != null) {
+            data.mark();
+            for (int i = 0; i < data.limit(); i++) {
+                if (i % itemsPerLine == 0 && i != 0) {
+                    sb.append(lineDelim);
+                }
+                sb.append(String.format("%02X", data.get(i)));
+                if (i % itemsPerLine != (itemsPerLine - 1) &&
+                        i != (data.limit() -1)) {
+                    sb.append(itemDelim);
+                }
+            }
+            data.reset();
+        }
+
+        return sb.toString();
+    }
+
+    private static void createManagerFactories()
+            throws GeneralSecurityException, IOException {
+        KeyStore keystore = KeyStore.getInstance("PKCS12");
+        KeyStore truststore = KeyStore.getInstance("PKCS12");
+        KeyStore empty_ts = KeyStore.getInstance("PKCS12");
+        char[] passphrase = passwd.toCharArray();
+
+        keystore.load(new FileInputStream(keyFilename), passphrase);
+        truststore.load(new FileInputStream(trustFilename), passphrase);
+        empty_ts.load(null, "".toCharArray());
+
+        KMF = KeyManagerFactory.getInstance("PKIX");
+        KMF.init(keystore, passphrase);
+        TMF = TrustManagerFactory.getInstance("PKIX");
+        TMF.init(truststore);
+        EMPTY_TMF = TrustManagerFactory.getInstance("PKIX");
+        EMPTY_TMF.init(truststore);
+    }
+
+    private static void checkEngineState(SSLEngine engine,
+            SSLEngineResult.HandshakeStatus expectedHSStat,
+            boolean expectedInboundDone, boolean expectedOutboundDone) {
+        if (engine.getHandshakeStatus() != expectedHSStat ||
+                engine.isInboundDone() != expectedInboundDone ||
+                engine.isOutboundDone() != expectedOutboundDone) {
+            throw new RuntimeException("Error: engine not in expected state\n" +
+                    "Expected: state = " + expectedHSStat +
+                    ", inDone = " + expectedInboundDone +
+                    ", outDone = " + expectedOutboundDone + "\n" +
+                    "Actual: state = " + engine.getHandshakeStatus() +
+                    ", inDone = " + engine.isInboundDone() +
+                    ", outDone = " + engine.isOutboundDone());
+        } else {
+            System.out.println((engine.getUseClientMode() ?
+                    "Client" : "Server") + " handshake status: " +
+                    engine.getHandshakeStatus() + ", inDone = " +
+                    engine.isInboundDone() + ", outDone = " +
+                    engine.isOutboundDone());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/ExtendedKeyEngine.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2004, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4981697
+ * @summary Rework the X509KeyManager to avoid incompatibility issues
+ * @author Brad R. Wetmore
+ *
+ * @run main/othervm -Djdk.tls.acknowledgeCloseNotify=true ExtendedKeyEngine
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class ExtendedKeyEngine {
+
+    private static boolean debug = false;
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;    // client
+    private SSLEngine ssle2;    // server
+
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer appOut1;         // write side of ssle1
+    private ByteBuffer appIn1;          // read side of ssle1
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine();
+        ssle2.setUseClientMode(false);
+        ssle2.setNeedClientAuth(true);
+    }
+
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) {
+
+            log("================");
+
+            result1 = ssle1.wrap(appOut1, oneToTwo);
+            result2 = ssle2.wrap(appOut2, twoToOne);
+
+            log("wrap1:  " + result1);
+            log("oneToTwo  = " + oneToTwo);
+            log("");
+
+            log("wrap2:  " + result2);
+            log("twoToOne  = " + twoToOne);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.flip();
+            twoToOne.flip();
+
+            log("----");
+
+            result1 = ssle1.unwrap(twoToOne, appIn1);
+            result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+            log("unwrap1: " + result1);
+            log("twoToOne  = " + twoToOne);
+            log("");
+
+            log("unwrap2: " + result2);
+            log("oneToTwo  = " + oneToTwo);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.compact();
+            twoToOne.compact();
+
+            /*
+             * If we've transfered all the data between app1 and app2,
+             * we try to close and see what that gets us.
+             */
+            if (!dataDone && (appOut1.limit() == appIn2.position()) &&
+                    (appOut2.limit() == appIn1.position())) {
+
+                checkTransfer(appOut1, appIn2);
+                checkTransfer(appOut2, appIn1);
+
+                log("Closing ssle1's *OUTBOUND*...");
+                ssle1.closeOutbound();
+                dataDone = true;
+            }
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        ExtendedKeyEngine test;
+
+        System.out.println("This test should run to completion");
+        test = new ExtendedKeyEngine(true);
+        test.createSSLEngines();
+        test.runTest();
+        System.out.println("Done!");
+
+        System.out.println("This test should fail with a Handshake Error");
+        test = new ExtendedKeyEngine(false);
+        test.createSSLEngines();
+
+        try {
+            test.runTest();
+        } catch (SSLHandshakeException e) {
+            System.out.println(
+                "Caught proper exception, should be 'no suites in common'");
+            e.printStackTrace();
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public ExtendedKeyEngine(boolean abs) throws Exception {
+        sslc = getSSLContext(keyFilename, trustFilename, abs);
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext(String keyFile, String trustFile,
+            boolean abs) throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        KeyManager [] kms = kmf.getKeyManagers();
+        if (abs) {
+            kms = new KeyManager [] {
+                new MyX509ExtendedKeyManager((X509ExtendedKeyManager)kms[0])
+            };
+        } else {
+            kms = new KeyManager [] {
+                new MyX509KeyManager((X509KeyManager)kms[0])
+            };
+        }
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+        TrustManager [] tms = tmf.getTrustManagers();
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kms, tms, null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        log("AppOut1 = " + appOut1);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("running delegated task...");
+                runnable.run();
+            }
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("Data transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/IllegalHandshakeMessage.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+//
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8180643
+ * @summary Illegal handshake message
+ * @ignore the dependent implementation details are changed
+ * @run main/othervm IllegalHandshakeMessage
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class IllegalHandshakeMessage {
+
+    public static void main(String args[]) throws Exception {
+        SSLContext context = SSLContext.getDefault();
+
+        SSLEngine cliEngine = context.createSSLEngine();
+        cliEngine.setUseClientMode(true);
+        SSLEngine srvEngine = context.createSSLEngine();
+        srvEngine.setUseClientMode(false);
+
+        SSLSession session = cliEngine.getSession();
+        int netBufferMax = session.getPacketBufferSize();
+        int appBufferMax = session.getApplicationBufferSize();
+
+        ByteBuffer cliToSrv = ByteBuffer.allocateDirect(netBufferMax);
+        ByteBuffer srvToCli = ByteBuffer.allocateDirect(netBufferMax);
+        ByteBuffer srvIBuff = ByteBuffer.allocateDirect(appBufferMax + 50);
+        ByteBuffer cliOBuff = ByteBuffer.wrap("I'm client".getBytes());
+        ByteBuffer srvOBuff = ByteBuffer.wrap("I'm server".getBytes());
+
+
+        System.out.println("client hello (handshake type(0xAB))");
+        SSLEngineResult cliRes = cliEngine.wrap(cliOBuff, cliToSrv);
+        System.out.println("Client wrap result: " + cliRes);
+        cliToSrv.flip();
+        if (cliToSrv.limit() > 7) {
+            cliToSrv.put(5, (byte)0xAB);    // use illegal handshake type
+            cliToSrv.put(7, (byte)0x80);    // use illegal message length
+        } else {
+            // unlikely
+            throw new Exception("No handshage message generated.");
+        }
+
+        try {
+            SSLEngineResult srvRes = srvEngine.unwrap(cliToSrv, srvIBuff);
+            System.out.println("Server unwrap result: " + srvRes);
+            runDelegatedTasks(srvRes, srvEngine);
+
+            srvRes = srvEngine.wrap(srvOBuff, srvToCli);
+            System.out.println("Server wrap result: " + srvRes);
+
+            throw new Exception(
+                "Unsupported handshake message is not handled properly.");
+        } catch (SSLException e) {
+            // get the expected exception
+            System.out.println("Expected exception: " + e);
+        }
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                System.out.println("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            System.out.println("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/IllegalRecordVersion.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8042449
+ * @summary Issue for negative byte major record version
+ * @ignore the dependent implementation details are changed
+ * @run main/othervm IllegalRecordVersion
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class IllegalRecordVersion {
+
+    public static void main(String args[]) throws Exception {
+        SSLContext context = SSLContext.getDefault();
+
+        SSLEngine cliEngine = context.createSSLEngine();
+        cliEngine.setUseClientMode(true);
+        SSLEngine srvEngine = context.createSSLEngine();
+        srvEngine.setUseClientMode(false);
+
+        SSLSession session = cliEngine.getSession();
+        int netBufferMax = session.getPacketBufferSize();
+        int appBufferMax = session.getApplicationBufferSize();
+
+        ByteBuffer cliToSrv = ByteBuffer.allocateDirect(netBufferMax);
+        ByteBuffer srvIBuff = ByteBuffer.allocateDirect(appBufferMax + 50);
+        ByteBuffer cliOBuff = ByteBuffer.wrap("I'm client".getBytes());
+
+
+        System.out.println("client hello (record version(0xa9, 0xa2))");
+        SSLEngineResult cliRes = cliEngine.wrap(cliOBuff, cliToSrv);
+        System.out.println("Client wrap result: " + cliRes);
+        cliToSrv.flip();
+        if (cliToSrv.limit() > 5) {
+            cliToSrv.put(1, (byte)0xa9);
+            cliToSrv.put(2, (byte)0xa2);
+        }
+
+        try {
+            srvEngine.unwrap(cliToSrv, srvIBuff);
+            throw new Exception(
+                "Cannot catch the unsupported record version issue");
+        } catch (SSLException e) {
+            // get the expected exception
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/LargeBufs.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2004, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4495742
+ * @summary Add non-blocking SSL/TLS functionality, usable with any
+ *      I/O abstraction
+ *
+ * This is to test larger buffer arrays, and make sure the maximum
+ * is being passed.
+ *
+ * @run main/othervm -Djsse.enableCBCProtection=false LargeBufs
+ *
+ * @author Brad R. Wetmore
+ * @key randomness
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+import java.util.Random;
+
+public class LargeBufs {
+
+    private static boolean debug = true;
+
+    private SSLContext sslc;
+    static private SSLEngine ssle1;     // client
+    static private SSLEngine ssle2;     // server
+
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer appOut1;         // write side of ssle1
+    private ByteBuffer appIn1;          // read side of ssle1
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    private int appBufferMax;
+    private int netBufferMax;
+    private int OFFSET = 37;
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine();
+        ssle2.setUseClientMode(false);
+        ssle2.setNeedClientAuth(true);
+    }
+
+    private void runTest(String cipher) throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+
+        System.out.println("Using " + cipher);
+        ssle1.setEnabledCipherSuites(new String [] { cipher });
+        ssle2.setEnabledCipherSuites(new String [] { cipher });
+
+        createBuffers();
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) {
+
+            log("================");
+
+            result1 = ssle1.wrap(appOut1, oneToTwo);
+            result2 = ssle2.wrap(appOut2, twoToOne);
+
+            if ((result1.bytesConsumed() != 0) &&
+                (result1.bytesConsumed() != appBufferMax) &&
+                (result1.bytesConsumed() != OFFSET)) {
+                throw new Exception("result1: " + result1);
+            }
+
+            if ((result2.bytesConsumed() != 0) &&
+                (result2.bytesConsumed() != appBufferMax) &&
+                (result2.bytesConsumed() != 2 * OFFSET)) {
+                throw new Exception("result2: " + result2);
+            }
+
+            log("wrap1:  " + result1);
+            log("oneToTwo  = " + oneToTwo);
+            log("");
+
+            log("wrap2:  " + result2);
+            log("twoToOne  = " + twoToOne);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.flip();
+            twoToOne.flip();
+
+            log("----");
+
+            result1 = ssle1.unwrap(twoToOne, appIn1);
+            result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+            if ((result1.bytesProduced() != 0) &&
+                (result1.bytesProduced() != appBufferMax) &&
+                (result1.bytesProduced() != 2 * OFFSET)) {
+                throw new Exception("result1: " + result1);
+            }
+
+            if ((result2.bytesProduced() != 0) &&
+                (result2.bytesProduced() != appBufferMax) &&
+                (result2.bytesProduced() != OFFSET)) {
+                throw new Exception("result1: " + result1);
+            }
+
+            log("unwrap1: " + result1);
+            log("twoToOne  = " + twoToOne);
+            log("");
+
+            log("unwrap2: " + result2);
+            log("oneToTwo  = " + oneToTwo);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.compact();
+            twoToOne.compact();
+
+            /*
+             * If we've transfered all the data between app1 and app2,
+             * we try to close and see what that gets us.
+             */
+            if (!dataDone && (appOut1.limit() == appIn2.position()) &&
+                    (appOut2.limit() == appIn1.position())) {
+
+                checkTransfer(appOut1, appIn2);
+                checkTransfer(appOut2, appIn1);
+
+                log("Closing ssle1's *OUTBOUND*...");
+                ssle1.closeOutbound();
+                dataDone = true;
+            }
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        LargeBufs test;
+
+        test = new LargeBufs();
+        test.runTest("SSL_RSA_WITH_RC4_128_MD5");
+
+        test = new LargeBufs();
+        test.runTest("SSL_RSA_WITH_3DES_EDE_CBC_SHA");
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public LargeBufs() throws Exception {
+        sslc = getSSLContext(keyFilename, trustFilename);
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext(String keyFile, String trustFile)
+            throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+
+        // The maximum application buffer should calculate like
+        // appBufferMax = session.getApplicationBufferSize();
+        // however, the getApplicationBufferSize() doesn't guarantee
+        // that the ability to concume or produce applicaton data upto
+        // the size. 16384 is the default JSSE implementation maximum
+        // application size that could be consumed and produced.
+        appBufferMax = 16384;
+        netBufferMax = session.getPacketBufferSize();
+
+        Random random = new Random();
+        byte [] one = new byte [appBufferMax * 5 + OFFSET];
+        byte [] two = new byte [appBufferMax * 5 + 2 * OFFSET];
+
+        random.nextBytes(one);
+        random.nextBytes(two);
+
+        appOut1 = ByteBuffer.wrap(one);
+        appOut2 = ByteBuffer.wrap(two);
+
+        appIn1 = ByteBuffer.allocate(appBufferMax * 6);
+        appIn2 = ByteBuffer.allocate(appBufferMax * 6);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        System.out.println("Testing arrays of: " + one.length +
+            " and " + two.length);
+
+        log("AppOut1 = " + appOut1);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("running delegated task...");
+                runnable.run();
+            }
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("Data transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLEngine/NoAuthClientAuth.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2003, 2011, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4495742
+ * @summary Demonstrate SSLEngine switch from no client auth to client auth.
+ * @run main/othervm NoAuthClientAuth SSLv3
+ * @run main/othervm NoAuthClientAuth TLSv1
+ * @run main/othervm NoAuthClientAuth TLSv1.1
+ * @run main/othervm NoAuthClientAuth TLSv1.2
+ * @author Brad R. Wetmore
+ */
+
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ *
+ * In this example, we do a rehandshake and make sure that completes
+ * correctly.
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+// Note that this test case depends on JSSE provider implementation details.
+public class NoAuthClientAuth {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static boolean debug = true;
+
+    private SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+    // the specified protocol
+    private static String tlsProtocol;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        tlsProtocol = args[0];
+
+        NoAuthClientAuth test = new NoAuthClientAuth();
+        test.runTest();
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public NoAuthClientAuth() throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest() throws Exception {
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult clientResult;   // results from client's last operation
+        SSLEngineResult serverResult;   // results from server's last operation
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        int hsCompleted = 0;
+        while (!isEngineClosed(clientEngine) ||
+                !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+            clientOut.rewind();
+
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            serverOut.rewind();
+
+            // Jeanfrancois:
+            // Here is the main rehandshaking step.
+            if (serverResult.getHandshakeStatus() ==
+                    HandshakeStatus.FINISHED) {
+                hsCompleted++;
+                log("\t" + hsCompleted + " handshake completed");
+                if (hsCompleted == 1) {
+                    try {
+                        serverEngine.getSession().getPeerCertificates();
+                        throw new Exception("Should have got exception");
+                    } catch (SSLPeerUnverifiedException e) {
+                        System.out.println("Caught proper exception." + e);
+                    }
+                    log("\tInvalidating session, setting client auth, " +
+                        " starting rehandshake");
+                    serverEngine.getSession().invalidate();
+                    serverEngine.setNeedClientAuth(true);
+                    serverEngine.beginHandshake();
+                } else if (hsCompleted == 2) {
+                    java.security.cert.Certificate [] certs =
+                        serverEngine.getSession().getPeerCertificates();
+                    System.out.println("Client Certificate(s) received");
+                    for (java.security.cert.Certificate c : certs) {
+                        System.out.println(c);
+                    }
+//                    log("Closing server.");
+//                    serverEngine.closeOutbound();
+                } // nothing.
+            }
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("----");
+
+            if (!clientEngine.isInboundDone()) {
+                clientResult = clientEngine.unwrap(sTOc, clientIn);
+                log("client unwrap: ", clientResult);
+                runDelegatedTasks(clientResult, clientEngine);
+                clientIn.clear();
+                sTOc.compact();
+            } else {
+                sTOc.clear();
+            }
+
+            if (!serverEngine.isInboundDone()) {
+                serverResult = serverEngine.unwrap(cTOs, serverIn);
+                log("server unwrap: ", serverResult);
+                runDelegatedTasks(serverResult, serverEngine);
+                serverIn.clear();
+                cTOs.compact();
+            } else {
+                cTOs.clear();
+            }
+
+            if (hsCompleted == 2) {
+                  log("Closing server.");
+                  serverEngine.closeOutbound();
+            }
+        }
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(false);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+        clientEngine.setEnabledProtocols(new String[] { tlsProtocol });
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSession/RenegotiateTLS13.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @run main/othervm -Djavax.net.debug=ssl RenegotiateTLS13
+ */
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+public class RenegotiateTLS13 {
+
+    static final String dataString = "This is a test";
+
+    // Run the server as a thread instead of the client
+    static boolean separateServerThread = false;
+
+    static String pathToStores = "../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    // Server ready flag
+    volatile static boolean serverReady = false;
+    // Turn on SSL debugging
+    static boolean debug = false;
+    // Server done flag
+    static boolean done = false;
+
+    // Main server code
+
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf;
+            sslssf = initContext().getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+
+        DataInputStream sslIS =
+            new DataInputStream(sslSocket.getInputStream());
+        String s = "";
+        while (s.compareTo("done") != 0) {
+            try {
+                s = sslIS.readUTF();
+                System.out.println("Received: " + s);
+            } catch (IOException e) {
+                throw e;
+            }
+        }
+        done = true;
+        sslSocket.close();
+    }
+
+    // Main client code
+    void doClientSide() throws Exception {
+
+        while (!serverReady) {
+            Thread.sleep(5);
+        }
+
+        SSLSocketFactory sslsf;
+        sslsf = initContext().getSocketFactory();
+
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        DataOutputStream sslOS =
+            new DataOutputStream(sslSocket.getOutputStream());
+
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("With " + dataString);
+
+        sslSocket.startHandshake();
+
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("With " + dataString);
+
+        sslSocket.startHandshake();
+
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("With " + dataString);
+        sslOS.writeUTF("done");
+
+        while (!done) {
+            Thread.sleep(5);
+        }
+        sslSocket.close();
+    }
+
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "ssl");
+
+        new RenegotiateTLS13();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    RenegotiateTLS13() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+
+    // Initialize context for TLS 1.3
+    SSLContext initContext() throws Exception {
+        System.out.println("Using TLS13");
+        SSLContext sc = SSLContext.getInstance("TLSv1.3");
+        KeyStore ks = KeyStore.getInstance(
+                new File(System.getProperty("javax.net.ssl.keyStore")),
+                passwd.toCharArray());
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
+                KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(ks, passwd.toCharArray());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+                TrustManagerFactory.getDefaultAlgorithm());
+        tmf.init(ks);
+        sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+        return sc;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSession/ResumeTLS13withSNI.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8211806
+ * @summary TLS 1.3 handshake server name indication is missing on a session resume
+ * @run main/othervm ResumeTLS13withSNI
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+import java.util.List;
+
+public class ResumeTLS13withSNI {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = false;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=ssl:handshake
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = true;
+
+    private static final ByteBuffer clientOut =
+            ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+    private static final ByteBuffer serverOut =
+            ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final char[] passphrase = "passphrase".toCharArray();
+
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private static final String HOST_NAME = "arf.yak.foo";
+    private static final SNIHostName SNI_NAME = new SNIHostName(HOST_NAME);
+    private static final SNIMatcher SNI_MATCHER =
+            SNIHostName.createSNIMatcher("arf\\.yak\\.foo");
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl:handshake");
+        }
+
+        KeyManagerFactory kmf = makeKeyManagerFactory(keyFilename,
+                passphrase);
+        TrustManagerFactory tmf = makeTrustManagerFactory(trustFilename,
+                passphrase);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        // Make client and server engines, then customize as needed
+        SSLEngine clientEngine = makeEngine(sslCtx, kmf, tmf, true);
+        SSLParameters cliSSLParams = clientEngine.getSSLParameters();
+        cliSSLParams.setServerNames(List.of(SNI_NAME));
+        clientEngine.setSSLParameters(cliSSLParams);
+        clientEngine.setEnabledProtocols(new String[] { "TLSv1.3" });
+
+        SSLEngine serverEngine = makeEngine(sslCtx, kmf, tmf, false);
+        SSLParameters servSSLParams = serverEngine.getSSLParameters();
+        servSSLParams.setSNIMatchers(List.of(SNI_MATCHER));
+        serverEngine.setSSLParameters(servSSLParams);
+
+        initialHandshake(clientEngine, serverEngine);
+
+        // Create a new client-side engine which can initiate TLS session
+        // resumption
+        SSLEngine newCliEngine = makeEngine(sslCtx, kmf, tmf, true);
+        newCliEngine.setEnabledProtocols(new String[] { "TLSv1.3" });
+        ByteBuffer resCliHello = getResumptionClientHello(newCliEngine);
+
+        dumpBuffer("Resumed ClientHello Data", resCliHello);
+
+        // Parse the client hello message and make sure it is a resumption
+        // hello and has SNI in it.
+        checkResumedClientHelloSNI(resCliHello);
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private static void initialHandshake(SSLEngine clientEngine,
+            SSLEngine serverEngine) throws Exception {
+        boolean dataDone = false;
+
+        // Create all the buffers
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+        ByteBuffer clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50);
+        ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        ByteBuffer sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        // results from client's last operation
+        SSLEngineResult clientResult;
+
+        // results from server's last operation
+        SSLEngineResult serverResult;
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        Exception clientException = null;
+        Exception serverException = null;
+
+        while (!dataDone) {
+            log("================");
+
+            try {
+                clientResult = clientEngine.wrap(clientOut, cTOs);
+                log("client wrap: ", clientResult);
+            } catch (Exception e) {
+                clientException = e;
+                System.err.println("Client wrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(clientEngine);
+            runDelegatedTasks(clientEngine);
+
+            log("----");
+
+            try {
+                serverResult = serverEngine.wrap(serverOut, sTOc);
+                log("server wrap: ", serverResult);
+            } catch (Exception e) {
+                serverException = e;
+                System.err.println("Server wrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(serverEngine);
+            runDelegatedTasks(serverEngine);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("--------");
+
+            try {
+                clientResult = clientEngine.unwrap(sTOc, clientIn);
+                log("client unwrap: ", clientResult);
+            } catch (Exception e) {
+                clientException = e;
+                System.err.println("Client unwrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(clientEngine);
+            runDelegatedTasks(clientEngine);
+
+            log("----");
+
+            try {
+                serverResult = serverEngine.unwrap(cTOs, serverIn);
+                log("server unwrap: ", serverResult);
+            } catch (Exception e) {
+                serverException = e;
+                System.err.println("Server unwrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(serverEngine);
+            runDelegatedTasks(serverEngine);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                dataDone = true;
+            }
+        }
+    }
+
+    /**
+     * The goal of this function is to start a simple TLS session resumption
+     * and get the client hello message data back so it can be inspected.
+     *
+     * @param clientEngine
+     *
+     * @return a ByteBuffer consisting of the ClientHello TLS record.
+     *
+     * @throws Exception if any processing goes wrong.
+     */
+    private static ByteBuffer getResumptionClientHello(SSLEngine clientEngine)
+            throws Exception {
+        // Create all the buffers
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+        ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        Exception clientException = null;
+
+        // results from client's last operation
+        SSLEngineResult clientResult;
+
+        // results from server's last operation
+        SSLEngineResult serverResult;
+
+        log("================");
+
+        // Start by having the client create a new ClientHello.  It should
+        // contain PSK info that allows it to attempt session resumption.
+        try {
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+        } catch (Exception e) {
+            clientException = e;
+            System.err.println("Client wrap() threw: " + e.getMessage());
+        }
+        logEngineStatus(clientEngine);
+        runDelegatedTasks(clientEngine);
+
+        log("----");
+
+        cTOs.flip();
+        return cTOs;
+    }
+
+    /**
+     * This method walks a ClientHello TLS record, looking for a matching
+     * server_name hostname value from the original handshake and a PSK
+     * extension, which indicates (in the context of this test) that this
+     * is a resumed handshake.
+     *
+     * @param resCliHello a ByteBuffer consisting of a complete TLS handshake
+     *      record that is a ClientHello message.  The position of the buffer
+     *      must be at the beginning of the TLS record header.
+     *
+     * @throws Exception if any of the consistency checks for the TLS record,
+     *      or handshake message fails.  It will also throw an exception if
+     *      either the server_name extension doesn't have a matching hostname
+     *      field or the pre_shared_key extension is not present.
+     */
+    private static void checkResumedClientHelloSNI(ByteBuffer resCliHello)
+            throws Exception {
+        boolean foundMatchingSNI = false;
+        boolean foundPSK = false;
+
+        // Advance past the following fields:
+        // TLS Record header (5 bytes)
+        resCliHello.position(resCliHello.position() + 5);
+
+        // Get the next byte and make sure it is a Client Hello
+        byte hsMsgType = resCliHello.get();
+        if (hsMsgType != 0x01) {
+            throw new Exception("Message is not a ClientHello, MsgType = " +
+                    hsMsgType);
+        }
+
+        // Skip past the length (3 bytes)
+        resCliHello.position(resCliHello.position() + 3);
+
+        // Protocol version should be TLSv1.2 (0x03, 0x03)
+        short chProto = resCliHello.getShort();
+        if (chProto != 0x0303) {
+            throw new Exception(
+                    "Client Hello protocol version is not TLSv1.2: Got " +
+                            String.format("0x%04X", chProto));
+        }
+
+        // Skip 32-bytes of random data
+        resCliHello.position(resCliHello.position() + 32);
+
+        // Get the legacy session length and skip that many bytes
+        int sessIdLen = Byte.toUnsignedInt(resCliHello.get());
+        resCliHello.position(resCliHello.position() + sessIdLen);
+
+        // Skip over all the cipher suites
+        int csLen = Short.toUnsignedInt(resCliHello.getShort());
+        resCliHello.position(resCliHello.position() + csLen);
+
+        // Skip compression methods
+        int compLen = Byte.toUnsignedInt(resCliHello.get());
+        resCliHello.position(resCliHello.position() + compLen);
+
+        // Parse the extensions.  Get length first, then walk the extensions
+        // List and look for the presence of the PSK extension and server_name.
+        // For server_name, make sure it is the same as what was provided
+        // in the original handshake.
+        System.err.println("ClientHello Extensions Check");
+        int extListLen = Short.toUnsignedInt(resCliHello.getShort());
+        while (extListLen > 0) {
+            // Get the Extension type and length
+            int extType = Short.toUnsignedInt(resCliHello.getShort());
+            int extLen = Short.toUnsignedInt(resCliHello.getShort());
+            switch (extType) {
+                case 0:                 // server_name
+                    System.err.println("* Found server_name Extension");
+                    int snListLen = Short.toUnsignedInt(resCliHello.getShort());
+                    while (snListLen > 0) {
+                        int nameType = Byte.toUnsignedInt(resCliHello.get());
+                        if (nameType == 0) {            // host_name
+                            int hostNameLen =
+                                    Short.toUnsignedInt(resCliHello.getShort());
+                            byte[] hostNameData = new byte[hostNameLen];
+                            resCliHello.get(hostNameData);
+                            String hostNameStr = new String(hostNameData);
+                            System.err.println("\tHostname: " + hostNameStr);
+                            if (hostNameStr.equals(HOST_NAME)) {
+                                foundMatchingSNI = true;
+                            }
+                            snListLen -= 3 + hostNameLen;   // type, len, data
+                        } else {                        // something else
+                            // We don't support anything else and cannot
+                            // know how to advance.  Throw an exception
+                            throw new Exception("Unknown server name type: " +
+                                    nameType);
+                        }
+                    }
+                    break;
+                case 41:                // pre_shared_key
+                    // We're not going to bother checking the value.  The
+                    // presence of the extension in the context of this test
+                    // is good enough to tell us this is a resumed ClientHello.
+                    foundPSK = true;
+                    System.err.println("* Found pre_shared_key Extension");
+                    resCliHello.position(resCliHello.position() + extLen);
+                    break;
+                default:
+                    System.err.format("* Found extension %d (%d bytes)\n",
+                            extType, extLen);
+                    resCliHello.position(resCliHello.position() + extLen);
+                    break;
+            }
+            extListLen -= extLen + 4;   // Ext type(2), length(2), data(var.)
+        }
+
+        // At the end of all the extension processing, either we've found
+        // both extensions and the server_name matches our expected value
+        // or we throw an exception.
+        if (!foundMatchingSNI) {
+            throw new Exception("Could not find a matching server_name");
+        } else if (!foundPSK) {
+            throw new Exception("Missing PSK extension, not a resumption?");
+        }
+    }
+
+    /**
+     * Create a TrustManagerFactory from a given keystore.
+     *
+     * @param tsPath the path to the trust store file.
+     * @param pass the password for the trust store.
+     *
+     * @return a new TrustManagerFactory built from the trust store provided.
+     *
+     * @throws GeneralSecurityException if any processing errors occur
+     *      with the Keystore instantiation or TrustManagerFactory creation.
+     * @throws IOException if any loading error with the trust store occurs.
+     */
+    private static TrustManagerFactory makeTrustManagerFactory(String tsPath,
+            char[] pass) throws GeneralSecurityException, IOException {
+        TrustManagerFactory tmf;
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        try (FileInputStream fsIn = new FileInputStream(tsPath)) {
+            ts.load(fsIn, pass);
+            tmf = TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ts);
+        }
+        return tmf;
+    }
+
+    /**
+     * Create a KeyManagerFactory from a given keystore.
+     *
+     * @param ksPath the path to the keystore file.
+     * @param pass the password for the keystore.
+     *
+     * @return a new TrustManagerFactory built from the keystore provided.
+     *
+     * @throws GeneralSecurityException if any processing errors occur
+     *      with the Keystore instantiation or KeyManagerFactory creation.
+     * @throws IOException if any loading error with the keystore occurs
+     */
+    private static KeyManagerFactory makeKeyManagerFactory(String ksPath,
+            char[] pass) throws GeneralSecurityException, IOException {
+        KeyManagerFactory kmf;
+        KeyStore ks = KeyStore.getInstance("JKS");
+
+        try (FileInputStream fsIn = new FileInputStream(ksPath)) {
+            ks.load(fsIn, pass);
+            kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, pass);
+        }
+        return kmf;
+    }
+
+    /**
+     * Create an SSLEngine instance from a given protocol specifier,
+     * KeyManagerFactory and TrustManagerFactory.
+     *
+     * @param ctx the SSLContext used to create the SSLEngine
+     * @param kmf an initialized KeyManagerFactory.  May be null.
+     * @param tmf an initialized TrustManagerFactory.  May be null.
+     * @param isClient true if it intended to create a client engine, false
+     *      for a server engine.
+     *
+     * @return an SSLEngine instance configured as a server and with client
+     *      authentication disabled.
+     *
+     * @throws GeneralSecurityException if any errors occur during the
+     *      creation of the SSLEngine.
+     */
+    private static SSLEngine makeEngine(SSLContext ctx,
+            KeyManagerFactory kmf, TrustManagerFactory tmf, boolean isClient)
+            throws GeneralSecurityException {
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        SSLEngine ssle = ctx.createSSLEngine("localhost", 8443);
+        ssle.setUseClientMode(isClient);
+        ssle.setNeedClientAuth(false);
+        return ssle;
+    }
+
+    private static void logEngineStatus(SSLEngine engine) {
+        log("\tCurrent HS State  " + engine.getHandshakeStatus().toString());
+        log("\tisInboundDone():  " + engine.isInboundDone());
+        log("\tisOutboundDone(): " + engine.isOutboundDone());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngine engine) throws Exception {
+
+        if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("    running delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            logEngineStatus(engine);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.err.println("The format of the SSLEngineResult is: \n" +
+                    "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                    "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+                result.getStatus() + "/" + hsStatus + ", " +
+                result.bytesConsumed() + "/" + result.bytesProduced() +
+                " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.err.println(str);
+        }
+    }
+
+    private static void dumpBuffer(String header, ByteBuffer data) {
+        data.mark();
+        System.err.format("========== %s ==========\n", header);
+        int i = 0;
+        while (data.remaining() > 0) {
+            if (i != 0 && i % 16 == 0) {
+                System.err.print("\n");
+            }
+            System.err.format("%02X ", data.get());
+            i++;
+        }
+        System.err.println();
+        data.reset();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSession/SessionCacheSizeTests.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2001, 2016, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4366807
+ * @summary Need new APIs to get/set session timeout and session cache size.
+ * @run main/othervm SessionCacheSizeTests
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.util.*;
+import java.security.*;
+
+/**
+ * Session cache size tests cover the following cases:
+ * 1. Effect of system property javax.net.ssl.SessionCacheSize (this
+ * property is not documented for public).
+ * 2. Reducing the cache size, results in uncaching of sessions if #of
+ * sessions present exceeds the new size.
+ * 3. Increasing the cache size, results in accomodating  new sessions if the
+ * number of cached sessions is the current size limit.
+ *
+ * Invairant for passing this test is, at any given time,
+ * #cached_sessions <= current_cache_size , for current_cache_size > 0
+ */
+
+public class SessionCacheSizeTests {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+
+    /*
+     * A limit on the number of connections at any given time
+     */
+    static int MAX_ACTIVE_CONNECTIONS = 4;
+
+    static final int FREE_PORT = 0;
+
+    void doServerSide(int serverConns) throws Exception {
+        try (SSLServerSocket sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(FREE_PORT)) {
+
+            // timeout to accept a connection
+            sslServerSocket.setSoTimeout(45000);
+
+            // make sure createdPorts++ is atomic
+            synchronized(serverPorts) {
+                int serverPort = sslServerSocket.getLocalPort();
+                System.out.printf("server #%d started on port %d%n",
+                        createdPorts, serverPort);
+                serverPorts[createdPorts++] = serverPort;
+
+                /*
+                 * Signal Client, we're ready for his connect.
+                 */
+                if (createdPorts == serverPorts.length) {
+                    serverReady = true;
+                }
+            }
+            int read = 0;
+            int nConnections = 0;
+
+            /*
+             * Divide the max connections among the available server ports.
+             * The use of more than one server port ensures creation of more
+             * than one session.
+             */
+            SSLSession sessions [] = new SSLSession [serverConns];
+            SSLSessionContext sessCtx = sslctx.getServerSessionContext();
+
+            while (nConnections < serverConns) {
+                try (SSLSocket sslSocket =
+                        (SSLSocket)sslServerSocket.accept()) {
+                    sslSocket.setSoTimeout(90000);      // timeout to read
+                    InputStream sslIS = sslSocket.getInputStream();
+                    OutputStream sslOS = sslSocket.getOutputStream();
+                    read = sslIS.read();
+                    sessions[nConnections] = sslSocket.getSession();
+                    sslOS.write(85);
+                    sslOS.flush();
+                    nConnections++;
+                }
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        int nConnections = 0;
+        SSLSocket sslSockets[] = new SSLSocket [MAX_ACTIVE_CONNECTIONS];
+        Vector sessions = new Vector();
+        SSLSessionContext sessCtx = sslctx.getClientSessionContext();
+        sessCtx.setSessionTimeout(0); // no limit
+
+        try {
+            while (nConnections < (MAX_ACTIVE_CONNECTIONS - 1)) {
+                // divide the connections among the available server ports
+                int serverPort = serverPorts [nConnections % (serverPorts.length)];
+                System.out.printf("client #%d connects to port %d%n",
+                        nConnections, serverPort);
+                sslSockets[nConnections] = (SSLSocket) sslsf.
+                            createSocket("localhost",
+                            serverPort);
+                InputStream sslIS = sslSockets[nConnections].getInputStream();
+                OutputStream sslOS = sslSockets[nConnections].getOutputStream();
+                sslOS.write(237);
+                sslOS.flush();
+                int read = sslIS.read();
+                SSLSession sess = sslSockets[nConnections].getSession();
+                if (!sessions.contains(sess))
+                    sessions.add(sess);
+                nConnections++;
+            }
+            System.out.println("Current cacheSize is set to: " +
+                                    sessCtx.getSessionCacheSize());
+            System.out.println();
+            System.out.println("Currently cached Sessions......");
+            System.out.println("============================================"
+                                    + "============================");
+            System.out.println("Session                                     "
+                                    + "      Session-last-accessTime");
+            System.out.println("============================================"
+                                    + "============================");
+            checkCachedSessions(sessCtx, nConnections);
+            // Change session cache size
+            sessCtx.setSessionCacheSize(2);
+            System.out.println("Session cache size changed to: "
+                            + sessCtx.getSessionCacheSize());
+            System.out.println();
+            checkCachedSessions(sessCtx, nConnections);
+
+            // Test the effect of increasing the cache size
+            sessCtx.setSessionCacheSize(3);
+            System.out.println("Session cache size changed to: "
+                            + sessCtx.getSessionCacheSize());
+            // create a new session
+            int serverPort = serverPorts [nConnections % (serverPorts.length)];
+            System.out.printf("client #%d connects to port %d%n",
+                    nConnections, serverPort);
+            sslSockets[nConnections] = (SSLSocket) sslsf.
+                            createSocket("localhost",
+                            serverPort);
+            InputStream sslIS = sslSockets[nConnections].getInputStream();
+            OutputStream sslOS = sslSockets[nConnections].getOutputStream();
+            sslOS.write(237);
+            sslOS.flush();
+            int read = sslIS.read();
+            SSLSession sess = sslSockets[nConnections].getSession();
+            if (!sessions.contains(sess))
+                sessions.add(sess);
+            nConnections++;
+
+            // test the number of sessions cached against the cache size
+            checkCachedSessions(sessCtx, nConnections);
+        } finally {
+            for (int i = 0; i < nConnections; i++) {
+                if (sslSockets[i] != null) {
+                    sslSockets[i].close();
+                }
+            }
+        }
+        System.out.println("Session cache size tests passed");
+    }
+
+    void checkCachedSessions(SSLSessionContext sessCtx,
+                int nConn) throws Exception {
+        int nSessions = 0;
+        Enumeration e = sessCtx.getIds();
+        int cacheSize = sessCtx.getSessionCacheSize();
+        SSLSession sess;
+
+        while (e.hasMoreElements()) {
+            sess = sessCtx.getSession((byte[]) e.nextElement());
+            long lastAccessedTime  = sess.getLastAccessedTime();
+                System.out.println(sess + "       "
+                        +  new Date(lastAccessedTime));
+
+            nSessions++;
+        }
+        System.out.println("--------------------------------------------"
+                                + "----------------------------");
+        if ((cacheSize > 0) && (nSessions > cacheSize)) {
+
+            // close all active connections before exiting
+            for (int conn = nConn; conn < MAX_ACTIVE_CONNECTIONS; conn++) {
+                SSLSocket s = (SSLSocket) sslsf.createSocket("localhost",
+                        serverPorts [conn % (serverPorts.length)]);
+                s.close();
+            }
+            throw new Exception("Session cache size test failed,"
+                + " current cache size: " + cacheSize + " #sessions cached: "
+                + nSessions);
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    /*
+     * #of ports > 1, guarantees creation of more than one session.
+     * Using four ports (one per each connection), we are able to create
+     * alteast four sessions.
+     */
+    int serverPorts[] = new int[]{0, 0, 0, 0};  // MAX_ACTIVE_CONNECTIONS: 4
+    int createdPorts = 0;
+    static SSLServerSocketFactory sslssf;
+    static SSLSocketFactory sslsf;
+    static SSLContext sslctx;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        // test the effect of javax.net.ssl.sessionCacheSize
+        System.setProperty("javax.net.ssl.sessionCacheSize", String.valueOf(0));
+
+        sslctx = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        KeyStore ks = KeyStore.getInstance("JKS");
+        try (FileInputStream fis = new FileInputStream(keyFilename)) {
+            ks.load(fis, passwd.toCharArray());
+        }
+        kmf.init(ks, passwd.toCharArray());
+        sslctx.init(kmf.getKeyManagers(), null, null);
+        sslssf = (SSLServerSocketFactory) sslctx.getServerSocketFactory();
+        sslsf = (SSLSocketFactory) sslctx.getSocketFactory();
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new SessionCacheSizeTests();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SessionCacheSizeTests() throws Exception {
+        /*
+         * create the SSLServerSocket and SSLSocket factories
+         */
+
+        /*
+         * Divide the max connections among the available server ports.
+         * The use of more than one server port ensures creation of more
+         * than one session.
+         */
+        int serverConns = MAX_ACTIVE_CONNECTIONS / (serverPorts.length);
+        int remainingConns = MAX_ACTIVE_CONNECTIONS % (serverPorts.length);
+
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                for (int i = 0; i < serverPorts.length; i++) {
+                    // distribute remaining connections among the
+                    // available ports
+                    if (i < remainingConns) {
+                        startServer(serverConns + 1, true);
+                    } else {
+                        startServer(serverConns, true);
+                    }
+                }
+                startClient(false);
+            } else {
+                startClient(true);
+                for (int i = 0; i < serverPorts.length; i++) {
+                    if (i < remainingConns) {
+                        startServer(serverConns + 1, false);
+                    } else {
+                        startServer(serverConns, false);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(final int nConns, boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide(nConns);
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        e.printStackTrace();
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide(nConns);
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread)
+                 throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSession/SessionTimeOutTests.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2001, 2017, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug   4366807
+ * @summary Need new APIs to get/set session timeout and session cache size.
+ * @run main/othervm SessionTimeOutTests
+ */
+
+import java.io.*;
+import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
+
+import javax.net.ssl.*;
+import java.util.*;
+import java.security.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Session reuse time-out tests cover the cases below:
+ * 1. general test, i.e timeout is set to x and session invalidates when
+ * its lifetime exceeds x.
+ * 2. Effect of changing the timeout limit.
+ * The test suite does not cover the default timeout(24 hours) usage. This
+ * case has been tested independently.
+ *
+ * Invariant for passing this test is, at any given time,
+ * lifetime of a session < current_session_timeout, such that
+ * current_session_timeout > 0, for all sessions cached by the session
+ * context.
+ */
+
+public class SessionTimeOutTests {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    private static int PORTS = 3;
+
+    /*
+     * Is the server ready to serve?
+     */
+    private final CountDownLatch serverCondition = new CountDownLatch(PORTS);
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     */
+
+    /*
+     * A limit on the number of connections at any given time
+     */
+    static int MAX_ACTIVE_CONNECTIONS = 3;
+
+    /*
+     * Divide the max connections among the available server ports.
+     * The use of more than one server port ensures creation of more
+     * than one session.
+     */
+    private static final int serverConns = MAX_ACTIVE_CONNECTIONS / PORTS;
+    private static final int remainingConns = MAX_ACTIVE_CONNECTIONS % PORTS;
+
+    private static final int TIMEOUT = 30000; // in millisecond
+
+    void doServerSide(int slot, int serverConns) throws Exception {
+
+        SSLServerSocket sslServerSocket
+                = (SSLServerSocket) sslssf.createServerSocket(0);
+        sslServerSocket.setSoTimeout(TIMEOUT);
+        serverPorts[slot] = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, one server is ready for its connect.
+         */
+        serverCondition.countDown();
+
+        for (int nConnections = 0; nConnections < serverConns; nConnections++) {
+            SSLSocket sslSocket = null;
+            try {
+                sslSocket = (SSLSocket) sslServerSocket.accept();
+            }  catch (SocketTimeoutException ste) {
+                System.out.println(
+                        "No incoming client connection. Ignore in server side.");
+                continue;
+            }
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+            sslIS.read();
+            sslSocket.getSession();
+            sslOS.write(85);
+            sslOS.flush();
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to zero
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        if (!serverCondition.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+            System.out.println(
+                    "The server side is not ready yet. Ignore in client side.");
+            return;
+        }
+
+        SSLSocket sslSockets[] = new SSLSocket[MAX_ACTIVE_CONNECTIONS];
+        Vector<SSLSession> sessions = new Vector<>();
+        SSLSessionContext sessCtx = sslctx.getClientSessionContext();
+
+        sessCtx.setSessionTimeout(10); // in secs
+        int timeout = sessCtx.getSessionTimeout();
+        for (int nConnections = 0; nConnections < MAX_ACTIVE_CONNECTIONS;
+                nConnections++) {
+            // divide the connections among the available server ports
+            try {
+                SSLSocket sslSocket = (SSLSocket) sslsf.createSocket();
+                sslSocket.connect(new InetSocketAddress("localhost",
+                        serverPorts[nConnections % serverPorts.length]),
+                        TIMEOUT);
+                sslSockets[nConnections] = sslSocket;
+            } catch (IOException ioe) {
+                // The server side may be impacted by naughty test cases or
+                // third party routines, and cannot accept connections.
+                //
+                // Just ignore the test if the connection cannot be
+                // established.
+                System.out.println(
+                        "Cannot make a connection in time. Ignore in client side.");
+                continue;
+            }
+
+            InputStream sslIS = sslSockets[nConnections].getInputStream();
+            OutputStream sslOS = sslSockets[nConnections].getOutputStream();
+            sslOS.write(237);
+            sslOS.flush();
+            sslIS.read();
+            SSLSession sess = sslSockets[nConnections].getSession();
+            if (!sessions.contains(sess))
+                sessions.add(sess);
+        }
+        System.out.println();
+        System.out.println("Current timeout is set to: " + timeout);
+        System.out.println("Testing SSLSessionContext.getSession()......");
+        System.out.println("========================================"
+                                + "=======================");
+        System.out.println("Session                                 "
+                                + "Session-     Session");
+        System.out.println("                                        "
+                                + "lifetime     timedout?");
+        System.out.println("========================================"
+                                + "=======================");
+
+        for (int i = 0; i < sessions.size(); i++) {
+            SSLSession session = (SSLSession) sessions.elementAt(i);
+            long currentTime  = System.currentTimeMillis();
+            long creationTime = session.getCreationTime();
+            long lifetime = (currentTime - creationTime) / 1000;
+
+            System.out.print(session + "      " + lifetime + "            ");
+            if (sessCtx.getSession(session.getId()) == null) {
+                if (lifetime < timeout)
+                    // sessions can be garbage collected before the timeout
+                    // limit is reached
+                    System.out.println("Invalidated before timeout");
+                else
+                    System.out.println("YES");
+            } else {
+                System.out.println("NO");
+                if ((timeout != 0) && (lifetime > timeout)) {
+                    throw new Exception("Session timeout test failed for the"
+                        + " obove session");
+                }
+            }
+            // change the timeout
+            if (i == ((sessions.size()) / 2)) {
+                System.out.println();
+                sessCtx.setSessionTimeout(2); // in secs
+                timeout = sessCtx.getSessionTimeout();
+                System.out.println("timeout is changed to: " + timeout);
+                System.out.println();
+           }
+        }
+
+        // check the ids returned by the enumerator
+        Enumeration<byte[]> e = sessCtx.getIds();
+        System.out.println("----------------------------------------"
+                                + "-----------------------");
+        System.out.println("Testing SSLSessionContext.getId()......");
+        System.out.println();
+
+        SSLSession nextSess = null;
+        SSLSession sess;
+        for (int i = 0; i < sessions.size(); i++) {
+            sess = (SSLSession)sessions.elementAt(i);
+            String isTimedout = "YES";
+            long currentTime  = System.currentTimeMillis();
+            long creationTime  = sess.getCreationTime();
+            long lifetime = (currentTime - creationTime) / 1000;
+
+            if (nextSess != null) {
+                if (isEqualSessionId(nextSess.getId(), sess.getId())) {
+                    isTimedout = "NO";
+                    nextSess = null;
+                }
+            } else if (e.hasMoreElements()) {
+                nextSess = sessCtx.getSession((byte[]) e.nextElement());
+                if ((nextSess != null) && isEqualSessionId(nextSess.getId(),
+                                        sess.getId())) {
+                    nextSess = null;
+                    isTimedout = "NO";
+                }
+            }
+
+            /*
+             * A session not invalidated even after it's timeout?
+             */
+            if ((timeout != 0) && (lifetime > timeout) &&
+                        (isTimedout.equals("NO"))) {
+                throw new Exception("Session timeout test failed for session: "
+                                + sess + " lifetime: " + lifetime);
+            }
+            System.out.print(sess + "      " + lifetime);
+            if (((timeout == 0) || (lifetime < timeout)) &&
+                                  (isTimedout == "YES")) {
+                isTimedout = "Invalidated before timeout";
+            }
+
+            System.out.println("            " + isTimedout);
+        }
+        for (int i = 0; i < sslSockets.length; i++) {
+            sslSockets[i].close();
+        }
+        System.out.println("----------------------------------------"
+                                 + "-----------------------");
+        System.out.println("Session timeout test passed");
+    }
+
+    boolean isEqualSessionId(byte[] id1, byte[] id2) {
+        if (id1.length != id2.length)
+           return false;
+        else {
+            for (int i = 0; i < id1.length; i++) {
+                if (id1[i] != id2[i]) {
+                   return false;
+                }
+            }
+            return true;
+        }
+    }
+
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    int serverPorts[] = new int[PORTS];
+    static SSLServerSocketFactory sslssf;
+    static SSLSocketFactory sslsf;
+    static SSLContext sslctx;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        sslctx = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(new FileInputStream(keyFilename), passwd.toCharArray());
+        kmf.init(ks, passwd.toCharArray());
+        sslctx.init(kmf.getKeyManagers(), null, null);
+        sslssf = (SSLServerSocketFactory) sslctx.getServerSocketFactory();
+        sslsf = (SSLSocketFactory) sslctx.getSocketFactory();
+
+        /*
+         * Start the tests.
+         */
+        new SessionTimeOutTests();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SessionTimeOutTests() throws Exception {
+
+        /*
+         * create the SSLServerSocket and SSLSocket factories
+         */
+
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                for (int i = 0; i < serverPorts.length; i++) {
+                    // distribute remaining connections among the
+                    // available ports
+                    if (i < remainingConns)
+                        startServer(i, (serverConns + 1), true);
+                    else
+                        startServer(i, serverConns, true);
+                }
+                startClient(false);
+            } else {
+                startClient(true);
+                for (int i = 0; i < PORTS; i++) {
+                    if (i < remainingConns)
+                        startServer(i, (serverConns + 1), false);
+                    else
+                        startServer(i, serverConns, false);
+                }
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(final int slot, final int nConns, boolean newThread)
+            throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide(slot, nConns);
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        e.printStackTrace();
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide(slot, nConns);
+            } catch (Exception e) {
+                serverException = e;
+            }
+        }
+    }
+
+    void startClient(boolean newThread)
+                 throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSession/TestEnabledProtocols.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 4416068 4478803 4479736
+ * @summary 4273544 JSSE request for function forceV3ClientHello()
+ *          4479736 setEnabledProtocols API does not work correctly
+ *          4478803 Need APIs to determine the protocol versions used in an SSL
+ *                  session
+ *          4701722 protocol mismatch exceptions should be consistent between
+ *                  SSLv3 and TLSv1
+ * @library /javax/net/ssl/templates
+ * @run main/othervm TestEnabledProtocols
+ * @author Ram Marti
+ */
+
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.security.Security;
+import java.util.Arrays;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+
+public class TestEnabledProtocols extends SSLSocketTemplate {
+
+    private final String[] serverProtocols;
+    private final String[] clientProtocols;
+    private final boolean exceptionExpected;
+    private final String selectedProtocol;
+
+    public TestEnabledProtocols(String[] serverProtocols,
+            String[] clientProtocols, boolean exceptionExpected,
+            String selectedProtocol) {
+        this.serverProtocols = serverProtocols;
+        this.clientProtocols = clientProtocols;
+        this.exceptionExpected = exceptionExpected;
+        this.selectedProtocol = selectedProtocol;
+    }
+
+    @Override
+    protected void configureServerSocket(SSLServerSocket sslServerSocket) {
+        sslServerSocket.setEnabledProtocols(serverProtocols);
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        try {
+            socket.startHandshake();
+
+            InputStream in = socket.getInputStream();
+            OutputStream out = socket.getOutputStream();
+            out.write(280);
+            in.read();
+        } catch (SSLHandshakeException se) {
+            // ignore it; this is part of the testing
+            // log it for debugging
+            System.out.println("Server SSLHandshakeException:");
+            se.printStackTrace(System.out);
+        } catch (InterruptedIOException ioe) {
+            // must have been interrupted, no harm
+        } catch (SSLException ssle) {
+            // The client side may have closed the socket.
+            System.out.println("Server SSLException:");
+            ssle.printStackTrace(System.out);
+        } catch (Exception e) {
+            System.out.println("Server exception:");
+            e.printStackTrace(System.out);
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket sslSocket) throws Exception {
+        try {
+            System.out.println("=== Starting new test run ===");
+            showProtocols("server", serverProtocols);
+            showProtocols("client", clientProtocols);
+
+            sslSocket.setEnabledProtocols(clientProtocols);
+            sslSocket.startHandshake();
+
+            String protocolName = sslSocket.getSession().getProtocol();
+            System.out.println("Protocol name after getSession is " +
+                protocolName);
+
+            if (protocolName.equals(selectedProtocol)) {
+                System.out.println("** Success **");
+            } else {
+                System.out.println("** FAILURE ** ");
+                throw new RuntimeException
+                    ("expected protocol " + selectedProtocol +
+                     " but using " + protocolName);
+            }
+
+            InputStream in = sslSocket.getInputStream();
+            OutputStream out = sslSocket.getOutputStream();
+            in.read();
+            out.write(280);
+        } catch (SSLHandshakeException e) {
+            if (!exceptionExpected) {
+                System.out.println(
+                        "Client got UNEXPECTED SSLHandshakeException:");
+                e.printStackTrace(System.out);
+                System.out.println("** FAILURE **");
+                throw new RuntimeException(e);
+            } else {
+                System.out.println(
+                        "Client got expected SSLHandshakeException:");
+                e.printStackTrace(System.out);
+                System.out.println("** Success **");
+            }
+        } catch (Exception e) {
+            System.out.println("Client got UNEXPECTED Exception:");
+            e.printStackTrace(System.out);
+            System.out.println("** FAILURE **");
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        runCase(new String[] { "TLSv1" },
+                new String[] { "TLSv1" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1" },
+                new String[] { "TLSv1", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "TLSv1" },
+                new String[] { "TLSv1", "SSLv3" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1" },
+                new String[] { "SSLv3", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "TLSv1" },
+                new String[] { "SSLv3" },
+                true, null);
+        runCase(new String[] { "TLSv1" },
+                new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                true, null);
+
+        runCase(new String[] { "TLSv1", "SSLv2Hello" },
+                new String[] { "TLSv1" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv2Hello" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv3" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv2Hello" },
+                new String[] { "SSLv3", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "TLSv1", "SSLv2Hello" },
+                new String[] { "SSLv3" },
+                true, null);
+        runCase(new String[] { "TLSv1", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                false, "TLSv1");
+
+        runCase(new String[] { "TLSv1", "SSLv3" },
+                new String[] { "TLSv1" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv3" },
+                new String[] { "TLSv1", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "TLSv1", "SSLv3" },
+                new String[] { "TLSv1", "SSLv3" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv3" },
+                new String[] { "SSLv3", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "TLSv1", "SSLv3" },
+                new String[] { "SSLv3" },
+                false, "SSLv3");
+        runCase(new String[] { "TLSv1", "SSLv3" },
+                new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                true, null);
+
+        runCase(new String[] { "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1" },
+                true, null);
+        runCase(new String[] { "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv3" },
+                false, "SSLv3");
+        runCase(new String[] { "SSLv3", "SSLv2Hello" },
+                new String[] { "SSLv3", "SSLv2Hello" },
+                false, "SSLv3");
+        runCase(new String[] { "SSLv3", "SSLv2Hello" },
+                new String[] { "SSLv3" },
+                false, "SSLv3");
+        runCase(new String[] { "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                false, "SSLv3");
+
+        runCase(new String[] { "SSLv3" },
+                new String[] { "TLSv1" },
+                true, null);
+        runCase(new String[] { "SSLv3" },
+                new String[] { "TLSv1", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "SSLv3" },
+                new String[] { "TLSv1", "SSLv3" },
+                false, "SSLv3");
+        runCase(new String[] { "SSLv3" },
+                new String[] { "SSLv3", "SSLv2Hello" },
+                true, null);
+        runCase(new String[] { "SSLv3" },
+                new String[] { "SSLv3" },
+                false, "SSLv3");
+        runCase(new String[] { "SSLv3" },
+                new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                true, null);
+
+        runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv2Hello" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv3" },
+                false, "TLSv1");
+        runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                new String[] { "SSLv3", "SSLv2Hello" },
+                false, "SSLv3");
+        runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                new String[] { "SSLv3" },
+                false, "SSLv3");
+        runCase(new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                new String[] { "TLSv1", "SSLv3", "SSLv2Hello" },
+                false, "TLSv1");
+    }
+
+    private static void runCase(
+            String[] serverProtocols,
+            String[] clientProtocols,
+            boolean exceptionExpected,
+            String selectedProtocol) throws Exception {
+        new TestEnabledProtocols(
+                serverProtocols,
+                clientProtocols,
+                exceptionExpected,
+                selectedProtocol).run();
+    }
+
+    private static void showProtocols(String name, String[] protocols) {
+        System.out.printf("Enabled protocols on the %s are: %s%n",
+                name,
+                Arrays.asList(protocols));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSocket/InputStreamClosure.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+//
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8216326
+ * @modules jdk.crypto.ec
+ * @library /javax/net/ssl/templates
+ * @summary SSLSocket stream close() does not close the associated socket
+ * @run main/othervm InputStreamClosure
+ */
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.SSLSocket;
+
+public class InputStreamClosure extends SSLSocketTemplate {
+
+    // Run the test case.
+    public static void main(String[] args) throws Exception {
+        (new InputStreamClosure()).run();
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        // here comes the test logic
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    /*
+     * Define the client side application of the test for the specified socket.
+     * This method is used if the returned value of
+     * isCustomizedClientConnection() is false.
+     *
+     * @param socket may be null is no client socket is generated.
+     *
+     * @see #isCustomizedClientConnection()
+     */
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        sslIS.close();
+        if (!socket.isClosed()) {
+            throw new Exception("Closing the SSLSocket InputStream does " +
+                    "not close the associated socket");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSocket/OutputStreamClosure.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+//
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8216326
+ * @modules jdk.crypto.ec
+ * @library /javax/net/ssl/templates
+ * @summary SSLSocket stream close() does not close the associated socket
+ * @run main/othervm OutputStreamClosure
+ */
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.SSLSocket;
+
+public class OutputStreamClosure extends SSLSocketTemplate {
+
+    // Run the test case.
+    public static void main(String[] args) throws Exception {
+        (new OutputStreamClosure()).run();
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        // here comes the test logic
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    /*
+     * Define the client side application of the test for the specified socket.
+     * This method is used if the returned value of
+     * isCustomizedClientConnection() is false.
+     *
+     * @param socket may be null is no client socket is generated.
+     *
+     * @see #isCustomizedClientConnection()
+     */
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        sslOS.close();
+        if (!socket.isClosed()) {
+            throw new Exception("Closing the SSLSocket OutputStream does " +
+                    "not close the associated socket");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/SSLSocket/Tls13PacketSize.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+//
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8221253
+ * @summary TLSv1.3 may generate TLSInnerPlainText longer than 2^14+1 bytes
+ * @modules jdk.crypto.ec
+ * @library /javax/net/ssl/templates
+ * @run main/othervm Tls13PacketSize
+ */
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.SSLSocket;
+
+public class Tls13PacketSize extends SSLSocketTemplate {
+    private static final byte[] appData = new byte[16385];
+    static {
+        for (int i = 0; i < appData.length; i++) {
+            appData[i] = (byte)('A' + (i % 26));
+        }
+    }
+
+    // Run the test case.
+    public static void main(String[] args) throws Exception {
+        (new Tls13PacketSize()).run();
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        // here comes the test logic
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        int extra = sslIS.available();
+        System.out.println("Server input bytes: " + extra);
+        // Considering the padding impact, the record plaintext is less
+        // than the TLSPlaintext.fragment length (2^14).
+        if (extra >= 16383) {    // 16383: 2^14 - 1 byte read above
+            throw new Exception(
+                    "Client record plaintext exceeds 2^14 octets: " + extra);
+        }
+
+        sslOS.write(appData);
+        sslOS.flush();
+    }
+
+    /*
+     * Define the client side application of the test for the specified socket.
+     * This method is used if the returned value of
+     * isCustomizedClientConnection() is false.
+     *
+     * @param socket may be null is no client socket is generated.
+     *
+     * @see #isCustomizedClientConnection()
+     */
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        socket.setEnabledProtocols(new String[] {"TLSv1.3"});
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(appData);
+        sslOS.flush();
+
+        sslIS.read();
+        int extra = sslIS.available();
+        System.out.println("Client input bytes: " + extra);
+        // Considering the padding impact, the record plaintext is less
+        // than the TLSPlaintext.fragment length (2^14).
+        if (extra >= 16383) {    // 16383: 2^14 - 1 byte read above
+            throw new Exception(
+                    "Server record plaintext exceeds 2^14 octets: " + extra);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ServerName/SSLSocketExplorerFailure.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/**
+ * @test
+ * @bug 7068321
+ * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server
+ * @library ../templates
+ * @build SSLCapabilities SSLExplorer
+ * @run main/othervm SSLSocketExplorerFailure SSLv2Hello,SSLv3
+ * @run main/othervm SSLSocketExplorerFailure SSLv3
+ * @run main/othervm SSLSocketExplorerFailure TLSv1
+ * @run main/othervm SSLSocketExplorerFailure TLSv1.1
+ * @run main/othervm SSLSocketExplorerFailure TLSv1.2
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.security.Security;
+
+public class SSLSocketExplorerFailure {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+
+        ServerSocket serverSocket = new ServerSocket(serverPort);
+
+        // Signal Client, we're ready for his connect.
+        serverPort = serverSocket.getLocalPort();
+        serverReady = true;
+
+        Socket socket = serverSocket.accept();
+        InputStream ins = socket.getInputStream();
+
+        byte[] buffer = new byte[0xFF];
+        int position = 0;
+        SSLCapabilities capabilities = null;
+        boolean failed = false;
+        try {
+            // Read the header of TLS record
+            while (position < SSLExplorer.RECORD_HEADER_SIZE) {
+                int count = SSLExplorer.RECORD_HEADER_SIZE - position;
+                int n = ins.read(buffer, position, count);
+                if (n < 0) {
+                    throw new Exception("unexpected end of stream!");
+                }
+                position += n;
+            }
+
+            int recordLength = SSLExplorer.getRequiredSize(buffer, 0, position);
+            if (buffer.length < recordLength) {
+                buffer = Arrays.copyOf(buffer, recordLength);
+            }
+
+            while (position < recordLength) {
+                int count = recordLength - position;
+                int n = ins.read(buffer, position, count);
+                if (n < 0) {
+                    throw new Exception("unexpected end of stream!");
+                }
+                position += n;
+            }
+
+            capabilities = SSLExplorer.explore(buffer, 0, recordLength);;
+            if (capabilities != null) {
+                System.out.println("Record version: " +
+                        capabilities.getRecordVersion());
+                System.out.println("Hello version: " +
+                        capabilities.getHelloVersion());
+            }
+
+            // want an I/O exception
+            throw new IOException("We just want a I/O exception");
+        } catch (Exception e) {
+            failed =  true;
+        }
+
+        // off course, the above explore failed. Faile to failure handler
+        SSLContext context = SSLContext.getInstance("TLS");
+        context.init(null, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+        ByteArrayInputStream bais =
+            new ByteArrayInputStream(buffer, 0, position);
+        SSLSocket sslSocket = (SSLSocket)sslsf.createSocket(socket, bais, true);
+
+        try {
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            if (!failed) {
+                sslOS.write(85);
+                sslOS.flush();
+            } else {
+                sslSocket.close();
+            }
+        } catch (Exception e) {
+            System.out.println("server exception " + e);
+        } finally {
+            sslSocket.close();
+            serverSocket.close();
+        }
+    }
+
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable the specified TLS protocol
+        sslSocket.setEnabledProtocols(supportedProtocols);
+
+        try {
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        } catch (Exception e) {
+            System.out.println("client exception " + e);
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    private static String[] supportedProtocols;    // supported protocols
+
+    private static void parseArguments(String[] args) {
+        supportedProtocols = args[0].split(",");
+    }
+
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new SSLSocketExplorerFailure();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SSLSocketExplorerFailure() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ServerName/SSLSocketSNISensitive.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,578 @@
+/*
+ * 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
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7068321
+ * @summary Support TLS Server Name Indication (SNI) Extension in JSSE Server
+ * @run main/othervm SSLSocketSNISensitive PKIX www.example.com
+ * @run main/othervm SSLSocketSNISensitive SunX509 www.example.com
+ * @run main/othervm SSLSocketSNISensitive PKIX www.example.net
+ * @run main/othervm SSLSocketSNISensitive SunX509 www.example.net
+ * @run main/othervm SSLSocketSNISensitive PKIX www.invalid.com
+ * @run main/othervm SSLSocketSNISensitive SunX509 www.invalid.com
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+// Note: this test case works only on TLS 1.2 and prior versions because of
+// the use of MD5withRSA signed certificate.
+public class SSLSocketSNISensitive {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNDE3MTIwNjA3WhcNMzMwMzI4MTIwNjA3WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBANY+7Enp+1S566kLcKk+qe4Ki6BxaHGZ+v7r\n" +
+        "vLksx9IQZCbAEf4YLbrZhKzKD3SPIJXyxPFwknAknIh3Knk8mViOZks7T8L3GnJr\n" +
+        "TBaVvDyTzDJum/QYiahfO2qpfN/Oya2UILmqsBAeLyWpzbQsAyWBXfoUtkOUgnzK\n" +
+        "fk6QAKYrAgMBAAGjgaUwgaIwHQYDVR0OBBYEFEtmQi7jT1ijXOafPsfkrLwSVu9e\n" +
+        "MGMGA1UdIwRcMFqAFEtmQi7jT1ijXOafPsfkrLwSVu9eoT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
+        "BQADgYEAkKWxMc4+ODk5WwLXXweB8/IKfVfrizNn0KLEgsZ6xNXFIXDpiPGAFcgl\n" +
+        "MzFO424JgyvUulsUc/X16Cnuwwntkk6KUG7vEV7h4o9sAV7Cax3gfQE/EZFb4ybn\n" +
+        "aBm1UsujMKd/ovqbbbxJbmOWzCeo0QfIGleDEyh3NBBZ0i11Kiw=\n" +
+        "-----END CERTIFICATE-----";
+
+    // web server certificate, www.example.com
+    static String targetCertStr_A =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICVTCCAb6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNDE3MTIwNjA4WhcNMzIwMTAzMTIwNjA4WjBVMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" +
+        "BAMTD3d3dy5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
+        "4zFp3PZNzsd3ZwG6FNNWO9eSN+UBymlf8oCwpKJM2tIinmMWvWIXnlx/2UXIfSAq\n" +
+        "QEG3aXkAFyEiGGpQlBbqcfrESsHsiz2pnnm5dG2v/eS0Bwz1jmcuNmwnh3UQw2Vl\n" +
+        "+BLk8ukdrLjiCT8jARiHExYf1Xg+wUqQ9y8NV26hdaUCAwEAAaNPME0wCwYDVR0P\n" +
+        "BAQDAgPoMB0GA1UdDgQWBBQwtx+gqzn2w4y82brXlp7tqBYEZDAfBgNVHSMEGDAW\n" +
+        "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQAJWo8B6Ud+\n" +
+        "/OU+UcZLihlfMX02OSlK2ZB7mfqpj2G3JT9yb0A+VbY3uuajmaYYIIxl3kXGz/n8\n" +
+        "M2Q/Ux/MDxG+IFKHC26Kuj4dAQgzjq2pILVPTE2QnaQTNCsgVZtTaC47SG9FRSoC\n" +
+        "qvnIvn/oTpKSqus76I1cR4joDtiV2OEuVw==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8
+    static String targetPrivateKey_A =
+        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAOMxadz2Tc7Hd2cB\n" +
+        "uhTTVjvXkjflAcppX/KAsKSiTNrSIp5jFr1iF55cf9lFyH0gKkBBt2l5ABchIhhq\n" +
+        "UJQW6nH6xErB7Is9qZ55uXRtr/3ktAcM9Y5nLjZsJ4d1EMNlZfgS5PLpHay44gk/\n" +
+        "IwEYhxMWH9V4PsFKkPcvDVduoXWlAgMBAAECgYAqX2nuIyXp3fvgA0twXOYlbRRB\n" +
+        "Rn3qAXM6qFPJsNeCrFR2k+aG1cev6nKR1FkLNTeMGnWZv06MAcr5IML8i7WXyG4C\n" +
+        "LY/C0gedn94FDKFlln+bTENwQTGjn4lKysDA+IuNpasTeMCajbic+dPByhIdTOjZ\n" +
+        "iMCyxbLfpk40zQopVQJBAPyfGmkeHB3GjdbdgujWCGKb2UxBa4O8dy3O4l2yizTn\n" +
+        "uUqMGcwGY4ciNSVvZQ7jKo4vDmkSuYib4/woPChaNfMCQQDmO0BQuSWYGNtSwV35\n" +
+        "lafZfX1dNCLKm1iNA6A12evXgvQiE9WT4mqionig0VZW16HtiY4/BkHOcos/K9Um\n" +
+        "ARQHAkA8mkaRtSF1my5nv1gqVz5Hua+VdZQ/VDUbDiiL5cszc+ulkJqXsWirAG/T\n" +
+        "fTe3LJQG7A7+8fkEZrF4yoY0AAA1AkEAotokezULj5N9iAL5SzL9wIzQYV4ggfny\n" +
+        "YATBjXXxKccakwQ+ndWZIiMUeoS4ssLialhTgucVI0fIkU2a/r/ifwJAc6e+5Pvh\n" +
+        "MghQj/U788Od/v6rgqz/NGsduZ7uilCMcWiwA73OR2MHMH/OIuoofuEPrfuV9isV\n" +
+        "xVXhgpKfP/pdOA==";
+
+    // web server certificate, www.example.net
+    static String targetCertStr_B =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICVTCCAb6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" +
+        "BAMTD3d3dy5leGFtcGxlLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
+        "2VlzF1fvWYczDChrUeJiLJ1M/dIShCaOTfYGiXfQGEZCAWTacUclwr+rVMnZ75/c\n" +
+        "wwg5pNdXRijxMil8DBTS1gFcIFQhosLHvzIAe6ULlg/xB+/L6KBz+NTWfo/2KF6t\n" +
+        "xatmcToNrCcwi7eUOfbzQje65Tizs56jJYem2m7Rk0ECAwEAAaNPME0wCwYDVR0P\n" +
+        "BAQDAgPoMB0GA1UdDgQWBBQT/FR0cAWcZQ7h0X79KGki34OSQjAfBgNVHSMEGDAW\n" +
+        "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQB67cPIT6fz\n" +
+        "6Ws8fBpYgW2ad4ci66i1WduBD9CpGFE+jRK2feRj6hvYBXocKj0AMWUFIEB2E3hA\n" +
+        "oIjxcf1GxIpHVl9DjlhxqXbA0Ktl7/NGNRlDSLTizOTl3FB1mMTlOGvXDVmpcFhl\n" +
+        "HuoP1hYvhTsBwPx5igGNchuPtDIUzL2mXw==\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetPrivateKey_B =
+        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBANlZcxdX71mHMwwo\n" +
+        "a1HiYiydTP3SEoQmjk32Bol30BhGQgFk2nFHJcK/q1TJ2e+f3MMIOaTXV0Yo8TIp\n" +
+        "fAwU0tYBXCBUIaLCx78yAHulC5YP8Qfvy+igc/jU1n6P9ihercWrZnE6DawnMIu3\n" +
+        "lDn280I3uuU4s7OeoyWHptpu0ZNBAgMBAAECgYEAl19H26sfhD+32rDPxZCgBShs\n" +
+        "dZ33zVe45i0Bcn4iTLWpxKTDyf7eGps4rO2DvfKdYqt40ggzvSZIjUH9JcDe8GmG\n" +
+        "d3m0ILB7pg4jsFlpyeHpTO8grPLxA1G9s3o0DoFpz/rooqgFfe/DrRDmRoOSkgfV\n" +
+        "/gseIbgJHRO/Ctyvdh0CQQD6uFd0HxhH1jl/JzvPzIH4LSnPcdEh9zsMEb6uzh75\n" +
+        "9qL+IHD5N2I/pYZTKqDFIwhJf701+LKag55AX/zrDt7rAkEA3e00AbnwanDMa6Wj\n" +
+        "+gFekUQveSVra38LiihzCkyVvQpFjbiF1rUhSNQ0dpU5/hmrYF0C6H9VXAesfkUY\n" +
+        "WhpDgwJAYjgZOop77piDycZK7isFt32p5XSHIzFBVocVFlH1XKM8UyXOXDNQL/Le\n" +
+        "XnJSrSf+NRzvuNcG0PVC56Ey6brXpQJAY4M4vcltt5zq3R5CQBmbGRJ1IyKXX3Vx\n" +
+        "bDslEqoyvri7ZYgnY5aG3UxiVgYmIf3KrgQnCLAIS6MZQumiuMxsFwJAK5pEG063\n" +
+        "9ngUof4fDMvZphqZjZR1zMKz/V/9ge0DWBINaqFgsgebNu+MyImsC8C6WKjGmV/2\n" +
+        "f1MY0D7sC2vU/Q==";
+
+    // web server certificate, www.invalid.com
+    static String targetCertStr_C =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICVTCCAb6gAwIBAgIBAzANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNDE3MTIwNjA5WhcNMzIwMTAzMTIwNjA5WjBVMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxGDAWBgNV\n" +
+        "BAMTD3d3dy5pbnZhbGlkLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA\n" +
+        "q6MyQwzCr2nJ41l0frmHL0qULSyW51MhevBC+1W28i0LE/efrmpwV3LdnlQEGFak\n" +
+        "DLDwtnff3iru8dSMcA7KdWVkivsE7ZTP+qFDaWBAy7XXiSsv6yZ2Nh4jJb0YcD28\n" +
+        "45zk2nAl5Az1/PuoTi1vpQxzFZKuBm1HGgz3MEZvBvMCAwEAAaNPME0wCwYDVR0P\n" +
+        "BAQDAgPoMB0GA1UdDgQWBBRRMifrND015Nm8N6gV5X7cg1YjjjAfBgNVHSMEGDAW\n" +
+        "gBRLZkIu409Yo1zmnz7H5Ky8ElbvXjANBgkqhkiG9w0BAQQFAAOBgQBjkUO6Ri/B\n" +
+        "uDC2gDMIyL5+NTe/1dPPQYM4HhCNa/KQYvU5lzCKO9Vpa+i+nyrUNNXUu8Tkyq4Y\n" +
+        "A+aGSm6+FT/i9rFwkYUdorBtD3KfQiwTIWrVERXBkWI5iZNaVZhx0TFy4vUpf65d\n" +
+        "QtwkbHpC66fdKc2EdLXkuY9KkmtZZJJ7YA==\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetPrivateKey_C =
+        "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKujMkMMwq9pyeNZ\n" +
+        "dH65hy9KlC0sludTIXrwQvtVtvItCxP3n65qcFdy3Z5UBBhWpAyw8LZ3394q7vHU\n" +
+        "jHAOynVlZIr7BO2Uz/qhQ2lgQMu114krL+smdjYeIyW9GHA9vOOc5NpwJeQM9fz7\n" +
+        "qE4tb6UMcxWSrgZtRxoM9zBGbwbzAgMBAAECgYASJDK40Y12Wvki1Z6xkkyOnBRj\n" +
+        "XfYpRykfxGtgA2RN3qLwHlk7Zzaul46DIKA6LlYynTUkJDF+Ww1cdDnP0lBlwcmM\n" +
+        "iD0ck3zYyYBLhQHuVbkK3SYE+ANRhM0icvvqANP2at/U4awQcPNEae/KCiecLNu3\n" +
+        "CJGqyhPDdrEAqPuJGQJBAN46pQC6l3yrcSYE2s53jSmsm2HVVOFlFXjU6k/RMTxG\n" +
+        "FfDJtGUAOQ37rPQ06ugr/gjLAmmPp+FXozaBdA32D80CQQDFuGRgv3WYqbglIcRL\n" +
+        "JRs6xlj9w1F97s/aiUenuwhIPNiUoRbV7mnNuZ/sGF0svOVE7SazRjuFX6UqL9Y9\n" +
+        "HzG/AkEA170pCI8cl4w8eUNHRB9trGKEKjMXhwVCFh7lJf2ZBcGodSzr8w2HVhrZ\n" +
+        "Ke7hiemDYffrbJ1oxmv05+o+x3r0lQJBAL6adVm2+FyFMFnLZXmzeb59O4jWY5bt\n" +
+        "Qz6/HG6bpO5OidMuP99YCHMkQQDOs/PO3Y5GuAoW6IY4n/Y9S2B80+0CQBl1/H9/\n" +
+        "0n/vrb6vW6Azds49tuS82RFAnOhtwTyBEajs08WF8rZQ3WD2RHJnH0+jjfL0anIp\n" +
+        "dQBSeNN7s7b6rRk=";
+
+    // This is a certificate for client
+    static String targetCertStr_D=
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICVDCCAb2gAwIBAgIBBTANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNDE3MTIwNjEwWhcNMzIwMTAzMTIwNjEwWjBUMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxFzAVBgNV\n" +
+        "BAMTDkludGVyT3AgVGVzdGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDo\n" +
+        "Q/KoAIAC2ljFfW2KwjnxTzi4NQJeUuk2seqKpsAY8x4O5dvixzUl6142zmljapqi\n" +
+        "bJloQVpfB+CEc5/l4h5gzGRVzkuqP1oPzDrpZ5GsvmvuHenV/TzCIgX1cLETzQVt\n" +
+        "6Rk06okoBPnw3hDJEJiEc1Rv7HCE8p/p+SaiHrskwwIDAQABo08wTTALBgNVHQ8E\n" +
+        "BAMCA+gwHQYDVR0OBBYEFPr91O33RIGfFSqza2AwQIgE4QswMB8GA1UdIwQYMBaA\n" +
+        "FEtmQi7jT1ijXOafPsfkrLwSVu9eMA0GCSqGSIb3DQEBBAUAA4GBANIDFYgAhoj3\n" +
+        "B8u1YpqeoEp2Lt9TwrYBshaIrbmBPCwCGio0JIsoov3n8BCSg5F+8MnOtPl+TjeO\n" +
+        "0Ug+7guPdCk/wg8YNxLHgSsQlpcNJDjWiErqmUPVrg5BPPQb65qMund6KTmMN0y6\n" +
+        "4EbSmxRpZO/N0/5oK4umTk0EeXKNekBj\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetPrivateKey_D =
+        "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOhD8qgAgALaWMV9\n" +
+        "bYrCOfFPOLg1Al5S6Tax6oqmwBjzHg7l2+LHNSXrXjbOaWNqmqJsmWhBWl8H4IRz\n" +
+        "n+XiHmDMZFXOS6o/Wg/MOulnkay+a+4d6dX9PMIiBfVwsRPNBW3pGTTqiSgE+fDe\n" +
+        "EMkQmIRzVG/scITyn+n5JqIeuyTDAgMBAAECgYBw37yIKp4LRONJLnhSq6sO+0n8\n" +
+        "Mz6waiiN/Q6XTQwj09pysQAYCGlqwSRrDAqpVsBJWO+Ae+oYLrLMi4hUZnwN75v3\n" +
+        "pe1nXlrD11RmPLXwBxqFxNSvAs2FgLHZEtwHI7Bn8KybT/8bGkQ8csLceInYtMDD\n" +
+        "MuTyy2KRk/pj60zIKQJBAPgebQiAH6viFQ88AwHaNvQhlUfwmSC1i6f8LVoeqaHC\n" +
+        "lnP0LJBwlyDeeEInhHrCR2ibnCB6I/Pig+49XQgabK8CQQDvpJwuGEbsOO+3rkJJ\n" +
+        "OpOw4toG0QJZdRnT6l8I6BlboQRZSfFh+lGGahvFXkxc4KdUpJ7QPtXU7HHk6Huk\n" +
+        "8RYtAkA9CW8VGj+wTuuTVdX/jKjcIa7RhbSFwWNbrcOSWdys+Gt+luCnn6rt4QyA\n" +
+        "aaxDbquWZkFgE+voQR7nap0KM0XtAkAznd0WAJymHM1lXt9gLoHJQ9N6TGKZKiPa\n" +
+        "BU1a+cMcfV4WbVrUo7oTnZ9Fr73681iXXq3mZOJh7lvJ1llreZIxAkBEnbiTgEf4\n" +
+        "tvku68jHcRbRPmdS7CBSWNEBaHLOm4pUSTcxVTKKMHw7vmM5/UYUxJ8QNKCYxn6O\n" +
+        "+vtiBwBawwzN";
+
+    static String[] serverCerts = {targetCertStr_A,
+                                targetCertStr_B, targetCertStr_C};
+    static String[] serverKeys  = {targetPrivateKey_A,
+                                targetPrivateKey_B, targetPrivateKey_C};
+    static String[] clientCerts = {targetCertStr_D};
+    static String[] clientKeys  = {targetPrivateKey_D};
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(false);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+        try {
+            sslSocket.setSoTimeout(5000);
+            sslSocket.setSoLinger(true, 5);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+
+            SSLSession session = sslSocket.getSession();
+            checkCertificate(session.getLocalCertificates(),
+                                                clientRequestedHostname);
+        } finally {
+            sslSocket.close();
+            sslServerSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(true);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+        SNIHostName serverName = new SNIHostName(clientRequestedHostname);
+        List<SNIServerName> serverNames = new ArrayList<>(1);
+        serverNames.add(serverName);
+        SSLParameters params = sslSocket.getSSLParameters();
+        params.setServerNames(serverNames);
+        sslSocket.setSSLParameters(params);
+
+        try {
+            sslSocket.setSoTimeout(5000);
+            sslSocket.setSoLinger(true, 5);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+
+            SSLSession session = sslSocket.getSession();
+            checkCertificate(session.getPeerCertificates(),
+                                                clientRequestedHostname);
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    private static void checkCertificate(Certificate[] certs,
+            String hostname) throws Exception {
+        if (certs != null && certs.length != 0) {
+            X509Certificate x509Cert = (X509Certificate)certs[0];
+
+            String subject = x509Cert.getSubjectX500Principal().getName();
+
+            if (!subject.contains(hostname)) {
+                throw new Exception(
+                        "Not the expected certificate: " + subject);
+            }
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;             // trust manager
+    private static String clientRequestedHostname; // server name indication
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        clientRequestedHostname = args[1];
+    }
+
+    private static SSLContext generateSSLContext(boolean isClient)
+            throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        ByteArrayInputStream is =
+                    new ByteArrayInputStream(trustedCertStr.getBytes());
+        Certificate trusedCert = cf.generateCertificate(is);
+        is.close();
+
+        ks.setCertificateEntry("RSA Export Signer", trusedCert);
+
+        String[] certStrs = null;
+        String[] keyStrs = null;
+        if (isClient) {
+            certStrs = clientCerts;
+            keyStrs = clientKeys;
+        } else {
+            certStrs = serverCerts;
+            keyStrs = serverKeys;
+        }
+
+        for (int i = 0; i < certStrs.length; i++) {
+            // generate the private key.
+            String keySpecStr = keyStrs[i];
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            String keyCertStr = certStrs[i];
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = new Certificate[2];
+            chain[0] = keyCert;
+            chain[1] = trusedCert;
+
+            // import the key entry.
+            ks.setKeyEntry("key-entry-" + i, priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLSv1.2");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(ks, passphrase);
+
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        ks = null;
+
+        return ctx;
+    }
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        // MD5 is used in this test case, don't disable MD5 algorithm.
+        Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "MD2, RSA keySize < 1024");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new SSLSocketSNISensitive();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SSLSocketSNISensitive() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died, because of " + e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died, because of " + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/Stapling/HttpsUrlConnClient.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,853 @@
+/*
+ * Copyright (c) 2015, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8046321 8153829
+ * @summary OCSP Stapling for TLS
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm HttpsUrlConnClient
+ */
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.net.Socket;
+import java.net.URL;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import javax.net.ssl.*;
+import java.security.KeyStore;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.GeneralSecurityException;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.Certificate;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+import sun.security.validator.ValidatorException;
+
+public class HttpsUrlConnClient {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    static final byte[] LINESEP = { 10 };
+    static final Base64.Encoder B64E = Base64.getMimeEncoder(64, LINESEP);
+
+    // Turn on TLS debugging
+    static boolean debug = true;
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    static String passwd = "passphrase";
+    static String ROOT_ALIAS = "root";
+    static String INT_ALIAS = "intermediate";
+    static String SSL_ALIAS = "ssl";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    // PKI components we will need for this test
+    static KeyStore rootKeystore;           // Root CA Keystore
+    static KeyStore intKeystore;            // Intermediate CA Keystore
+    static KeyStore serverKeystore;         // SSL Server Keystore
+    static KeyStore trustStore;             // SSL Client trust store
+    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
+    static int rootOcspPort;                // Port number for root OCSP
+    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
+    static int intOcspPort;                 // Port number for intermed. OCSP
+
+    // Extra configuration parameters and constants
+    static final String[] TLS13ONLY = new String[] { "TLSv1.3" };
+    static final String[] TLS12MAX =
+            new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
+
+    private static final String SIMPLE_WEB_PAGE = "<HTML>\n" +
+            "<HEAD><Title>Web Page!</Title></HEAD>\n" +
+            "<BODY><H1>Web Page!</H1></BODY>\n</HTML>";
+    private static final SimpleDateFormat utcDateFmt =
+            new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+    public static void main(String[] args) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl:handshake");
+        }
+
+        System.setProperty("javax.net.ssl.keyStore", "");
+        System.setProperty("javax.net.ssl.keyStorePassword", "");
+        System.setProperty("javax.net.ssl.trustStore", "");
+        System.setProperty("javax.net.ssl.trustStorePassword", "");
+
+        // Create the PKI we will use for the test and start the OCSP servers
+        createPKI();
+        utcDateFmt.setTimeZone(TimeZone.getTimeZone("GMT"));
+
+        testPKIXParametersRevEnabled(TLS12MAX);
+        testPKIXParametersRevEnabled(TLS13ONLY);
+
+        // shut down the OCSP responders before finishing the test
+        intOcsp.stop();
+        rootOcsp.stop();
+    }
+
+    /**
+     * Do a basic connection using PKIXParameters with revocation checking
+     * enabled and client-side OCSP disabled.  It will only pass if all
+     * stapled responses are present, valid and have a GOOD status.
+     */
+    static void testPKIXParametersRevEnabled(String[] allowedProts)
+            throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        cliParams.protocols = allowedProts;
+        ServerParameters servParams = new ServerParameters();
+        serverReady = false;
+
+        System.out.println("=====================================");
+        System.out.println("Stapling enabled, PKIXParameters with");
+        System.out.println("Revocation checking enabled ");
+        System.out.println("=====================================");
+
+        // Set the certificate entry in the intermediate OCSP responder
+        // with a revocation date of 8 hours ago.
+        X509Certificate sslCert =
+                (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,
+                        new Date(System.currentTimeMillis() -
+                                TimeUnit.HOURS.toMillis(8))));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Set up revocation checking on the client with no client-side
+        // OCSP fall-back
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+        Security.setProperty("ocsp.enable", "false");
+
+        HttpsUrlConnClient sslTest = new HttpsUrlConnClient(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) {
+            if (tr.clientExc != null) {
+                throw tr.clientExc;
+            } else {
+                throw new RuntimeException(
+                        "Expected client failure, but the client succeeded");
+            }
+        }
+
+        // In this case the server should also have thrown an exception
+        // because of the client alert
+        if (tr.serverExc instanceof SSLHandshakeException) {
+            if (!tr.serverExc.getMessage().contains(
+                    "bad_certificate_status_response")) {
+                throw tr.serverExc;
+            }
+        }
+
+        System.out.println("                PASS");
+        System.out.println("=====================================\n");
+    }
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide(ServerParameters servParams) throws Exception {
+
+        // Selectively enable or disable the feature
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                Boolean.toString(servParams.enabled));
+
+        // Set all the other operating parameters
+        System.setProperty("jdk.tls.stapling.cacheSize",
+                Integer.toString(servParams.cacheSize));
+        System.setProperty("jdk.tls.stapling.cacheLifetime",
+                Integer.toString(servParams.cacheLifetime));
+        System.setProperty("jdk.tls.stapling.responseTimeout",
+                Integer.toString(servParams.respTimeout));
+        System.setProperty("jdk.tls.stapling.responderURI", servParams.respUri);
+        System.setProperty("jdk.tls.stapling.responderOverride",
+                Boolean.toString(servParams.respOverride));
+        System.setProperty("jdk.tls.stapling.ignoreExtensions",
+                Boolean.toString(servParams.ignoreExts));
+
+        // Set keystores and trust stores for the server
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(serverKeystore, passwd.toCharArray());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(trustStore);
+
+        SSLContext sslc = SSLContext.getInstance("TLS");
+        sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        SSLServerSocketFactory sslssf = sslc.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+        log("Server Port is " + serverPort);
+
+        // Dump the private key in PKCS8 format, not encrypted.  This
+        // key dump can be used if the traffic was captured using tcpdump
+        // or wireshark to look into the encrypted packets for debug purposes.
+        if (debug) {
+            byte[] keybytes = serverKeystore.getKey(SSL_ALIAS,
+                    passwd.toCharArray()).getEncoded();
+            PKCS8EncodedKeySpec p8spec = new PKCS8EncodedKeySpec(keybytes);
+            StringBuilder keyPem = new StringBuilder();
+            keyPem.append("-----BEGIN PRIVATE KEY-----\n");
+            keyPem.append(B64E.encodeToString(p8spec.getEncoded())).append("\n");
+            keyPem.append("-----END PRIVATE KEY-----\n");
+            log("Private key is:\n" + keyPem.toString());
+        }
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+                BufferedReader in = new BufferedReader(
+                    new InputStreamReader(sslSocket.getInputStream()));
+                OutputStream out = sslSocket.getOutputStream()) {
+            StringBuilder hdrBldr = new StringBuilder();
+            String line;
+            while ((line = in.readLine()) != null && !line.isEmpty()) {
+                hdrBldr.append(line).append("\n");
+            }
+            String headerText = hdrBldr.toString();
+            log("Header Received: " + headerText.length() + " bytes\n" +
+                    headerText);
+
+            StringBuilder sb = new StringBuilder();
+            sb.append("HTTP/1.0 200 OK\r\n");
+            sb.append("Date: ").append(utcDateFmt.format(new Date())).
+                    append("\r\n");
+            sb.append("Content-Type: text/html\r\n");
+            sb.append("Content-Length: ").append(SIMPLE_WEB_PAGE.length());
+            sb.append("\r\n\r\n");
+            out.write(sb.toString().getBytes("UTF-8"));
+            out.write(SIMPLE_WEB_PAGE.getBytes("UTF-8"));
+            out.flush();
+            log("Server replied with:\n" + sb.toString() + SIMPLE_WEB_PAGE);
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide(ClientParameters cliParams) throws Exception {
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !serverReady); i++) {
+            Thread.sleep(50);
+        }
+        if (!serverReady) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        // Selectively enable or disable the feature
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                Boolean.toString(cliParams.enabled));
+
+        HtucSSLSocketFactory sockFac = new HtucSSLSocketFactory(cliParams);
+        HttpsURLConnection.setDefaultSSLSocketFactory(sockFac);
+        URL location = new URL("https://localhost:" + serverPort);
+        HttpsURLConnection tlsConn =
+                (HttpsURLConnection)location.openConnection();
+        tlsConn.setConnectTimeout(5000);
+        tlsConn.setReadTimeout(5000);
+        tlsConn.setDoInput(true);
+
+        try (InputStream in = tlsConn.getInputStream()) {
+            // Check the response
+            if (debug && tlsConn.getResponseCode() !=
+                    HttpURLConnection.HTTP_OK) {
+                log("Received HTTP error: " + tlsConn.getResponseCode() +
+                        " - " + tlsConn.getResponseMessage());
+                throw new IOException("HTTP error: " +
+                        tlsConn.getResponseCode());
+            }
+
+            int contentLength = tlsConn.getContentLength();
+            if (contentLength == -1) {
+                contentLength = Integer.MAX_VALUE;
+            }
+            byte[] response = new byte[contentLength > 2048 ? 2048 :
+                contentLength];
+            int total = 0;
+            while (total < contentLength) {
+                int count = in.read(response, total, response.length - total);
+                if (count < 0)
+                    break;
+
+                total += count;
+                log("Read " + count + " bytes (" + total + " total)");
+                if (total >= response.length && total < contentLength) {
+                    response = Arrays.copyOf(response, total * 2);
+                }
+            }
+            response = Arrays.copyOf(response, total);
+            String webPage = new String(response, 0, total);
+            if (debug) {
+                log("Web page:\n" + webPage);
+            }
+        }
+    }
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    HttpsUrlConnClient(ClientParameters cliParams,
+            ServerParameters servParams) throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(servParams, true);
+                startClient(cliParams, false);
+            } else {
+                startClient(cliParams, true);
+                startServer(servParams, false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+    }
+
+    /**
+     * Checks a validation failure to see if it failed for the reason we think
+     * it should.  This comes in as an SSLException of some sort, but it
+     * encapsulates a CertPathValidatorException at some point in the
+     * exception stack.
+     *
+     * @param e the exception thrown at the top level
+     * @param reason the underlying CertPathValidatorException BasicReason
+     * we are expecting it to have.
+     *
+     * @return true if the reason matches up, false otherwise.
+     */
+    static boolean checkClientValidationFailure(Exception e,
+            BasicReason reason) {
+        boolean result = false;
+
+        // Locate the CertPathValidatorException.  If one
+        // Does not exist, then it's an automatic failure of
+        // the test.
+        Throwable curExc = e;
+        CertPathValidatorException cpve = null;
+        while (curExc != null) {
+            if (curExc instanceof CertPathValidatorException) {
+                cpve = (CertPathValidatorException)curExc;
+            }
+            curExc = curExc.getCause();
+        }
+
+        // If we get through the loop and cpve is null then we
+        // we didn't find CPVE and this is a failure
+        if (cpve != null) {
+            if (cpve.getReason() == reason) {
+                result = true;
+            } else {
+                System.out.println("CPVE Reason Mismatch: Expected = " +
+                        reason + ", Actual = " + cpve.getReason());
+            }
+        } else {
+            System.out.println("Failed to find an expected CPVE");
+        }
+
+        return result;
+    }
+
+    TestResult getResult() {
+        TestResult tr = new TestResult();
+        tr.clientExc = clientException;
+        tr.serverExc = serverException;
+        return tr;
+    }
+
+    final void startServer(ServerParameters servParams, boolean newThread)
+            throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doServerSide(servParams);
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide(servParams);
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    final void startClient(ClientParameters cliParams, boolean newThread)
+            throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doClientSide(cliParams);
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide(cliParams);
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(debug);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(debug);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert an X509Certificate to be displayed
+     *
+     * @return the String output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+
+    /**
+     * Log a message on stdout
+     *
+     * @param message The message to log
+     */
+    private static void log(String message) {
+        if (debug) {
+            System.out.println(message);
+        }
+    }
+
+    // The following two classes are Simple nested class to group a handful
+    // of configuration parameters used before starting a client or server.
+    // We'll just access the data members directly for convenience.
+    static class ClientParameters {
+        boolean enabled = true;
+        PKIXBuilderParameters pkixParams = null;
+        PKIXRevocationChecker revChecker = null;
+        String[] protocols = null;
+        String[] cipherSuites = null;
+
+        ClientParameters() { }
+    }
+
+    static class ServerParameters {
+        boolean enabled = true;
+        int cacheSize = 256;
+        int cacheLifetime = 3600;
+        int respTimeout = 5000;
+        String respUri = "";
+        boolean respOverride = false;
+        boolean ignoreExts = false;
+
+        ServerParameters() { }
+    }
+
+    static class TestResult {
+        Exception serverExc = null;
+        Exception clientExc = null;
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Test Result:\n").
+                append("\tServer Exc = ").append(serverExc).append("\n").
+                append("\tClient Exc = ").append(clientExc).append("\n");
+            return sb.toString();
+        }
+    }
+
+    static class HtucSSLSocketFactory extends SSLSocketFactory {
+        ClientParameters params;
+        SSLContext sslc = SSLContext.getInstance("TLS");
+
+        HtucSSLSocketFactory(ClientParameters cliParams)
+                throws GeneralSecurityException {
+            super();
+
+            // Create the Trust Manager Factory using the PKIX variant
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+
+            // If we have a customized pkixParameters then use it
+            if (cliParams.pkixParams != null) {
+                // LIf we have a customized PKIXRevocationChecker, add
+                // it to the PKIXBuilderParameters.
+                if (cliParams.revChecker != null) {
+                    cliParams.pkixParams.addCertPathChecker(
+                            cliParams.revChecker);
+                }
+
+                ManagerFactoryParameters trustParams =
+                        new CertPathTrustManagerParameters(
+                                cliParams.pkixParams);
+                tmf.init(trustParams);
+            } else {
+                tmf.init(trustStore);
+            }
+
+            sslc.init(null, tmf.getTrustManagers(), null);
+            params = cliParams;
+        }
+
+        @Override
+        public Socket createSocket(Socket s, String host, int port,
+                boolean autoClose) throws IOException {
+            Socket sock =  sslc.getSocketFactory().createSocket(s, host, port,
+                    autoClose);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress host, int port)
+                throws IOException {
+            Socket sock = sslc.getSocketFactory().createSocket(host, port);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress host, int port,
+                InetAddress localAddress, int localPort) throws IOException {
+            Socket sock = sslc.getSocketFactory().createSocket(host, port,
+                    localAddress, localPort);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(String host, int port)
+                throws IOException {
+            Socket sock =  sslc.getSocketFactory().createSocket(host, port);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(String host, int port,
+                InetAddress localAddress, int localPort)
+                throws IOException {
+            Socket sock =  sslc.getSocketFactory().createSocket(host, port,
+                    localAddress, localPort);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public String[] getDefaultCipherSuites() {
+            return sslc.getDefaultSSLParameters().getCipherSuites();
+        }
+
+        @Override
+        public String[] getSupportedCipherSuites() {
+            return sslc.getSupportedSSLParameters().getCipherSuites();
+        }
+
+        private void customizeSocket(Socket sock) {
+            if (sock instanceof SSLSocket) {
+                SSLSocket sslSock = (SSLSocket)sock;
+                if (params.protocols != null) {
+                    sslSock.setEnabledProtocols(params.protocols);
+                }
+                if (params.cipherSuites != null) {
+                    sslSock.setEnabledCipherSuites(params.cipherSuites);
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/Stapling/SSLEngineWithStapling.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,694 @@
+/*
+ * Copyright (c) 2015, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8046321 8153829
+ * @summary OCSP Stapling for TLS
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm SSLEngineWithStapling
+ */
+
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.math.BigInteger;
+import java.security.*;
+import java.nio.*;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CertSelector;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+public class SSLEngineWithStapling {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = true;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    static final String passwd = "passphrase";
+    static final String ROOT_ALIAS = "root";
+    static final String INT_ALIAS = "intermediate";
+    static final String SSL_ALIAS = "ssl";
+
+    // PKI components we will need for this test
+    static KeyStore rootKeystore;           // Root CA Keystore
+    static KeyStore intKeystore;            // Intermediate CA Keystore
+    static KeyStore serverKeystore;         // SSL Server Keystore
+    static KeyStore trustStore;             // SSL Client trust store
+    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
+    static int rootOcspPort;                // Port number for root OCSP
+    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
+    static int intOcspPort;                 // Port number for intermed. OCSP
+
+    // Extra configuration parameters and constants
+    static final String[] TLS13ONLY = new String[] { "TLSv1.3" };
+    static final String[] TLS12MAX =
+            new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl:handshake");
+        }
+
+        // Create the PKI we will use for the test and start the OCSP servers
+        createPKI();
+
+        // Set the certificate entry in the intermediate OCSP responder
+        // with a revocation date of 8 hours ago.
+        X509Certificate sslCert =
+                (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,
+                        new Date(System.currentTimeMillis() -
+                                TimeUnit.HOURS.toMillis(8))));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Create a list of TLS protocol configurations we can use to
+        // drive tests with different handshaking models.
+        List<String[]> allowedProtList = List.of(TLS12MAX, TLS13ONLY);
+
+        for (String[] protocols : allowedProtList) {
+            SSLEngineWithStapling test = new SSLEngineWithStapling();
+            try {
+                test.runTest(protocols);
+                throw new RuntimeException("Expected failure due to " +
+                        "revocation did not occur");
+            } catch (Exception e) {
+                if (!checkClientValidationFailure(e,
+                        CertPathValidatorException.BasicReason.REVOKED)) {
+                    System.out.println(
+                            "*** Didn't find the exception we wanted");
+                    throw e;
+                }
+            }
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLEngineWithStapling() throws Exception {
+        System.setProperty("javax.net.ssl.keyStore", "");
+        System.setProperty("javax.net.ssl.keyStorePassword", "");
+        System.setProperty("javax.net.ssl.trustStore", "");
+        System.setProperty("javax.net.ssl.trustStorePassword", "");
+
+        // Enable OCSP Stapling on both client and server sides, but turn off
+        // client-side OCSP for revocation checking.  This ensures that the
+        // revocation information from the test has to come via stapling.
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                Boolean.toString(true));
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                Boolean.toString(true));
+        Security.setProperty("ocsp.enable", "false");
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest(String[] protocols) throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines(protocols);
+        createBuffers();
+
+        SSLEngineResult clientResult;   // results from client's last operation
+        SSLEngineResult serverResult;   // results from server's last operation
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        while (!isEngineClosed(clientEngine) ||
+                !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("----");
+
+            clientResult = clientEngine.unwrap(sTOc, clientIn);
+            log("client unwrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            log("server unwrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                log("\tClosing clientEngine's *OUTBOUND*...");
+                clientEngine.closeOutbound();
+                dataDone = true;
+            }
+        }
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines(String[] protocols) throws Exception {
+        // Initialize the KeyManager and TrustManager for the server
+        KeyManagerFactory servKmf = KeyManagerFactory.getInstance("PKIX");
+        servKmf.init(serverKeystore, passwd.toCharArray());
+        TrustManagerFactory servTmf =
+                TrustManagerFactory.getInstance("PKIX");
+        servTmf.init(trustStore);
+
+        // Initialize the TrustManager for the client with revocation checking
+        PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        pkixParams.setRevocationEnabled(true);
+        ManagerFactoryParameters mfp =
+                new CertPathTrustManagerParameters(pkixParams);
+        TrustManagerFactory cliTmf =
+                TrustManagerFactory.getInstance("PKIX");
+        cliTmf.init(mfp);
+
+        // Create the SSLContexts from the factories
+        SSLContext servCtx = SSLContext.getInstance("TLS");
+        servCtx.init(servKmf.getKeyManagers(), servTmf.getTrustManagers(),
+                null);
+        SSLContext cliCtx = SSLContext.getInstance("TLS");
+        cliCtx.init(null, cliTmf.getTrustManagers(), null);
+
+
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.
+         */
+        serverEngine = servCtx.createSSLEngine();
+        serverEngine.setEnabledProtocols(protocols);
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(false);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = cliCtx.createSSLEngine("client", 80);
+        clientEngine.setEnabledProtocols(protocols);
+        clientEngine.setUseClientMode(true);
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+
+        /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(logging);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(logging);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert an X509Certificate to be displayed
+     *
+     * @return the String output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+
+    /**
+     * Checks a validation failure to see if it failed for the reason we think
+     * it should.  This comes in as an SSLException of some sort, but it
+     * encapsulates a CertPathValidatorException at some point in the
+     * exception stack.
+     *
+     * @param e the exception thrown at the top level
+     * @param reason the underlying CertPathValidatorException BasicReason
+     * we are expecting it to have.
+     *
+     * @return true if the reason matches up, false otherwise.
+     */
+    static boolean checkClientValidationFailure(Exception e,
+            CertPathValidatorException.BasicReason reason) {
+        boolean result = false;
+
+        // Locate the CertPathValidatorException.  If one
+        // Does not exist, then it's an automatic failure of
+        // the test.
+        Throwable curExc = e;
+        CertPathValidatorException cpve = null;
+        while (curExc != null) {
+            if (curExc instanceof CertPathValidatorException) {
+                cpve = (CertPathValidatorException)curExc;
+            }
+            curExc = curExc.getCause();
+        }
+
+        // If we get through the loop and cpve is null then we
+        // we didn't find CPVE and this is a failure
+        if (cpve != null) {
+            if (cpve.getReason() == reason) {
+                result = true;
+            } else {
+                System.out.println("CPVE Reason Mismatch: Expected = " +
+                        reason + ", Actual = " + cpve.getReason());
+            }
+        } else {
+            System.out.println("Failed to find an expected CPVE");
+        }
+
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/Stapling/SSLSocketWithStapling.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,1299 @@
+/*
+ * Copyright (c) 2015, 2017, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8046321 8153829
+ * @summary OCSP Stapling for TLS
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm SSLSocketWithStapling
+ */
+
+import java.io.*;
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.ServerSocket;
+import java.security.GeneralSecurityException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import javax.net.ssl.*;
+import java.security.KeyStore;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.Certificate;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.cert.PKIXRevocationChecker.Option;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+public class SSLSocketWithStapling {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    // Turn on TLS debugging
+    static final boolean debug = false;
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    static String passwd = "passphrase";
+    static String ROOT_ALIAS = "root";
+    static String INT_ALIAS = "intermediate";
+    static String SSL_ALIAS = "ssl";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    // PKI components we will need for this test
+    static KeyStore rootKeystore;           // Root CA Keystore
+    static KeyStore intKeystore;            // Intermediate CA Keystore
+    static KeyStore serverKeystore;         // SSL Server Keystore
+    static KeyStore trustStore;             // SSL Client trust store
+    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
+    static int rootOcspPort;                // Port number for root OCSP
+    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
+    static int intOcspPort;                 // Port number for intermed. OCSP
+
+    // Extra configuration parameters and constants
+    static final String[] TLS13ONLY = new String[] { "TLSv1.3" };
+    static final String[] TLS12MAX =
+            new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+    public static void main(String[] args) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl:handshake");
+        }
+
+        try {
+            // Create the PKI we will use for the test and start the OCSP servers
+            createPKI();
+
+            testAllDefault(false);
+            testAllDefault(true);
+            testPKIXParametersRevEnabled(false);
+            testPKIXParametersRevEnabled(true);
+            testRevokedCertificate(false);
+            testRevokedCertificate(true);
+            testRevokedIntermediate(false);
+            testRevokedIntermediate(true);
+            testMissingIntermediate(false);
+            testMissingIntermediate(true);
+            testHardFailFallback(false);
+            testHardFailFallback(true);
+            testSoftFailFallback(false);
+            testSoftFailFallback(true);
+            testLatencyNoStaple(false, false);
+            testLatencyNoStaple(false, true);
+            testLatencyNoStaple(true, false);
+            testLatencyNoStaple(true, true);
+        } finally {
+            // shut down the OCSP responders before finishing the test
+            intOcsp.stop();
+            rootOcsp.stop();
+        }
+    }
+
+    /**
+     * Default test using no externally-configured PKIXBuilderParameters
+     */
+    static void testAllDefault(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+                new HashMap<>();
+
+        // We will prove revocation checking is disabled by marking the SSL
+        // certificate as revoked.  The test would only pass if revocation
+        // checking did not happen.
+        X509Certificate sslCert =
+                (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
+        Date fiveMinsAgo = new Date(System.currentTimeMillis() -
+                TimeUnit.MINUTES.toMillis(5));
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,
+                        fiveMinsAgo));
+        intOcsp.updateStatusDb(revInfo);
+
+        System.out.println("=======================================");
+        System.out.println("Stapling enabled, default configuration");
+        System.out.println("=======================================");
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (tr.clientExc != null) {
+            throw tr.clientExc;
+        } else if (tr.serverExc != null) {
+            throw tr.serverExc;
+        }
+
+        // Return the ssl certificate to non-revoked status
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        System.out.println("                PASS");
+        System.out.println("=======================================\n");
+    }
+
+    /**
+     * Do a basic connection using PKIXParameters with revocation checking
+     * enabled and client-side OCSP disabled.  It will only pass if all
+     * stapled responses are present, valid and have a GOOD status.
+     */
+    static void testPKIXParametersRevEnabled(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+
+        System.out.println("=====================================");
+        System.out.println("Stapling enabled, PKIXParameters with");
+        System.out.println("Revocation checking enabled ");
+        System.out.println("=====================================");
+
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+        Security.setProperty("ocsp.enable", "false");
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (tr.clientExc != null) {
+            throw tr.clientExc;
+        } else if (tr.serverExc != null) {
+            throw tr.serverExc;
+        }
+
+        System.out.println("                PASS");
+        System.out.println("=====================================\n");
+    }
+
+    /**
+     * Perform a test where the certificate is revoked and placed in the
+     * TLS handshake.  Client-side OCSP is disabled, so this test will only
+     * pass if the OCSP response is found, since we will check the
+     * CertPathValidatorException reason for revoked status.
+     */
+    static void testRevokedCertificate(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+                new HashMap<>();
+
+        // We will prove revocation checking is disabled by marking the SSL
+        // certificate as revoked.  The test would only pass if revocation
+        // checking did not happen.
+        X509Certificate sslCert =
+                (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
+        Date fiveMinsAgo = new Date(System.currentTimeMillis() -
+                TimeUnit.MINUTES.toMillis(5));
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,
+                        fiveMinsAgo));
+        intOcsp.updateStatusDb(revInfo);
+
+        System.out.println("============================================");
+        System.out.println("Stapling enabled, detect revoked certificate");
+        System.out.println("============================================");
+
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+        Security.setProperty("ocsp.enable", "false");
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) {
+            if (tr.clientExc != null) {
+                throw tr.clientExc;
+            } else {
+                throw new RuntimeException(
+                        "Expected client failure, but the client succeeded");
+            }
+        }
+
+        // Return the ssl certificate to non-revoked status
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        System.out.println("                 PASS");
+        System.out.println("=======================================\n");
+    }
+
+    /**
+     * Perform a test where the intermediate CA certificate is revoked and
+     * placed in the TLS handshake.  Client-side OCSP is disabled, so this
+     * test will only pass if the OCSP response for the intermediate CA is
+     * found and placed into the CertificateStatus or Certificate message
+     * (depending on the protocol version) since we will check
+     * the CertPathValidatorException reason for revoked status.
+     */
+    static void testRevokedIntermediate(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+                new HashMap<>();
+
+        // We will prove revocation checking is disabled by marking the SSL
+        // certificate as revoked.  The test would only pass if revocation
+        // checking did not happen.
+        X509Certificate intCACert =
+                (X509Certificate)intKeystore.getCertificate(INT_ALIAS);
+        Date fiveMinsAgo = new Date(System.currentTimeMillis() -
+                TimeUnit.MINUTES.toMillis(5));
+        revInfo.put(intCACert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_REVOKED,
+                        fiveMinsAgo));
+        rootOcsp.updateStatusDb(revInfo);
+
+        System.out.println("===============================================");
+        System.out.println("Stapling enabled, detect revoked CA certificate");
+        System.out.println("===============================================");
+
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+        Security.setProperty("ocsp.enable", "false");
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (!checkClientValidationFailure(tr.clientExc, BasicReason.REVOKED)) {
+            if (tr.clientExc != null) {
+                throw tr.clientExc;
+            } else {
+                throw new RuntimeException(
+                        "Expected client failure, but the client succeeded");
+            }
+        }
+
+        // Return the ssl certificate to non-revoked status
+        revInfo.put(intCACert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        System.out.println("                 PASS");
+        System.out.println("=======================================\n");
+    }
+
+    /**
+     * Test a case where OCSP stapling is attempted, but partially occurs
+     * because the root OCSP responder is unreachable.  This should use a
+     * default hard-fail behavior.
+     */
+    static void testMissingIntermediate(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+
+        // Make the OCSP responder reject connections
+        rootOcsp.rejectConnections();
+
+        System.out.println("=======================================");
+        System.out.println("Stapling enbled in client and server,");
+        System.out.println("but root OCSP responder disabled.");
+        System.out.println("PKIXParameters with Revocation checking");
+        System.out.println("enabled.");
+        System.out.println("=======================================");
+
+        Security.setProperty("ocsp.enable", "false");
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (!checkClientValidationFailure(tr.clientExc,
+                BasicReason.UNDETERMINED_REVOCATION_STATUS)) {
+            if (tr.clientExc != null) {
+                throw tr.clientExc;
+            } else {
+                throw new RuntimeException(
+                        "Expected client failure, but the client succeeded");
+            }
+        }
+
+        System.out.println("                 PASS");
+        System.out.println("=======================================\n");
+
+        // Make root OCSP responder accept connections
+        rootOcsp.acceptConnections();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!rootOcsp.isServerReady()) {
+            throw new RuntimeException("Root OCSP responder not ready yet");
+        }
+    }
+
+    /**
+     * Test a case where client-side stapling is attempted, but does not
+     * occur because OCSP responders are unreachable.  This should use a
+     * default hard-fail behavior.
+     */
+    static void testHardFailFallback(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+
+        // make OCSP responders reject connections
+        intOcsp.rejectConnections();
+        rootOcsp.rejectConnections();
+
+        System.out.println("=======================================");
+        System.out.println("Stapling enbled in client and server,");
+        System.out.println("but OCSP responders disabled.");
+        System.out.println("PKIXParameters with Revocation checking");
+        System.out.println("enabled.");
+        System.out.println("=======================================");
+
+        Security.setProperty("ocsp.enable", "true");
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (!checkClientValidationFailure(tr.clientExc,
+                BasicReason.UNDETERMINED_REVOCATION_STATUS)) {
+            if (tr.clientExc != null) {
+                throw tr.clientExc;
+            } else {
+                throw new RuntimeException(
+                        "Expected client failure, but the client succeeded");
+            }
+        }
+
+        System.out.println("                 PASS");
+        System.out.println("=======================================\n");
+
+        // Make OCSP responders accept connections
+        intOcsp.acceptConnections();
+        rootOcsp.acceptConnections();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
+                !rootOcsp.isServerReady())); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+    }
+
+    /**
+     * Test a case where client-side stapling is attempted, but does not
+     * occur because OCSP responders are unreachable.  Client-side OCSP
+     * checking is enabled for this, with SOFT_FAIL.
+     */
+    static void testSoftFailFallback(boolean isTls13) throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+
+        // make OCSP responders reject connections
+        intOcsp.rejectConnections();
+        rootOcsp.rejectConnections();
+
+        System.out.println("=======================================");
+        System.out.println("Stapling enbled in client and server,");
+        System.out.println("but OCSP responders disabled.");
+        System.out.println("PKIXParameters with Revocation checking");
+        System.out.println("enabled and SOFT_FAIL.");
+        System.out.println("=======================================");
+
+        Security.setProperty("ocsp.enable", "true");
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+        CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+        cliParams.revChecker =
+                (PKIXRevocationChecker)cpv.getRevocationChecker();
+        cliParams.revChecker.setOptions(EnumSet.of(Option.SOFT_FAIL));
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+        if (tr.clientExc != null) {
+            throw tr.clientExc;
+        } else if (tr.serverExc != null) {
+            throw tr.serverExc;
+        }
+
+        // make sure getSoftFailExceptions is not empty
+        if (cliParams.revChecker.getSoftFailExceptions().isEmpty()) {
+            throw new Exception("No soft fail exceptions");
+        }
+
+        System.out.println("                 PASS");
+        System.out.println("=======================================\n");
+
+
+        // Make OCSP responders accept connections
+        intOcsp.acceptConnections();
+        rootOcsp.acceptConnections();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
+                        !rootOcsp.isServerReady())); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+    }
+
+    /**
+     * This test initiates stapling from the client, but the server does not
+     * support OCSP stapling for this connection.  In this case it happens
+     * because the latency of the OCSP responders is longer than the server
+     * is willing to wait.  To keep the test streamlined, we will set the server
+     * latency to a 1 second wait, and set the responder latency to 3 seconds.
+     *
+     * @param fallback if we allow client-side OCSP fallback, which
+     * will change the result from the client failing with CPVE (no fallback)
+     * to a pass (fallback active).
+     */
+    static void testLatencyNoStaple(Boolean fallback, boolean isTls13)
+            throws Exception {
+        ClientParameters cliParams = new ClientParameters();
+        ServerParameters servParams = new ServerParameters();
+        if (isTls13) {
+            cliParams.protocols = TLS13ONLY;
+            servParams.protocols = TLS13ONLY;
+        } else {
+            cliParams.protocols = TLS12MAX;
+            servParams.protocols = TLS12MAX;
+        }
+        serverReady = false;
+
+        // Give a 1 second delay before running the test.
+        intOcsp.setDelay(3000);
+        rootOcsp.setDelay(3000);
+        Thread.sleep(1000);
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
+                        !rootOcsp.isServerReady())); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        System.out.println("========================================");
+        System.out.println("Stapling enbled in client.  Server does");
+        System.out.println("not support stapling due to OCSP latency.");
+        System.out.println("PKIXParameters with Revocation checking");
+        System.out.println("enabled, client-side OCSP checking is.");
+        System.out.println(fallback ? "enabled" : "disabled");
+        System.out.println("========================================");
+
+        Security.setProperty("ocsp.enable", fallback.toString());
+        cliParams.pkixParams = new PKIXBuilderParameters(trustStore,
+                new X509CertSelector());
+        cliParams.pkixParams.setRevocationEnabled(true);
+        servParams.respTimeout = 1000;
+
+        SSLSocketWithStapling sslTest = new SSLSocketWithStapling(cliParams,
+                servParams);
+        TestResult tr = sslTest.getResult();
+
+        if (fallback) {
+            if (tr.clientExc != null) {
+                throw tr.clientExc;
+            } else if (tr.serverExc != null) {
+                throw tr.serverExc;
+            }
+        } else {
+            if (!checkClientValidationFailure(tr.clientExc,
+                    BasicReason.UNDETERMINED_REVOCATION_STATUS)) {
+                if (tr.clientExc != null) {
+                    throw tr.clientExc;
+                } else {
+                    throw new RuntimeException(
+                        "Expected client failure, but the client succeeded");
+                }
+            }
+        }
+        System.out.println("                 PASS");
+        System.out.println("========================================\n");
+
+        // Remove the OCSP responder latency
+        intOcsp.setDelay(0);
+        rootOcsp.setDelay(0);
+        Thread.sleep(1000);
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && (!intOcsp.isServerReady() ||
+                !rootOcsp.isServerReady())); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady() || !rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+    }
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide(ServerParameters servParams) throws Exception {
+
+        // Selectively enable or disable the feature
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                Boolean.toString(servParams.enabled));
+
+        // Set all the other operating parameters
+        System.setProperty("jdk.tls.stapling.cacheSize",
+                Integer.toString(servParams.cacheSize));
+        System.setProperty("jdk.tls.stapling.cacheLifetime",
+                Integer.toString(servParams.cacheLifetime));
+        System.setProperty("jdk.tls.stapling.responseTimeout",
+                Integer.toString(servParams.respTimeout));
+        System.setProperty("jdk.tls.stapling.responderURI", servParams.respUri);
+        System.setProperty("jdk.tls.stapling.responderOverride",
+                Boolean.toString(servParams.respOverride));
+        System.setProperty("jdk.tls.stapling.ignoreExtensions",
+                Boolean.toString(servParams.ignoreExts));
+
+        // Set keystores and trust stores for the server
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(serverKeystore, passwd.toCharArray());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(trustStore);
+
+        SSLContext sslc = SSLContext.getInstance("TLS");
+        sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        SSLServerSocketFactory sslssf = new CustomizedServerSocketFactory(sslc,
+                servParams.protocols, servParams.ciphers);
+
+        try (SSLServerSocket sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(serverPort)) {
+
+            serverPort = sslServerSocket.getLocalPort();
+
+            /*
+             * Signal Client, we're ready for his connect.
+             */
+            serverReady = true;
+
+            try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+                    InputStream sslIS = sslSocket.getInputStream();
+                    OutputStream sslOS = sslSocket.getOutputStream()) {
+                int numberIn = sslIS.read();
+                int numberSent = 85;
+                log("Server received number: " + numberIn);
+                sslOS.write(numberSent);
+                sslOS.flush();
+                log("Server sent number: " + numberSent);
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide(ClientParameters cliParams) throws Exception {
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !serverReady); i++) {
+            Thread.sleep(50);
+        }
+        if (!serverReady) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        // Selectively enable or disable the feature
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                Boolean.toString(cliParams.enabled));
+
+        // Create the Trust Manager Factory using the PKIX variant
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+
+        // If we have a customized pkixParameters then use it
+        if (cliParams.pkixParams != null) {
+            // LIf we have a customized PKIXRevocationChecker, add
+            // it to the PKIXBuilderParameters.
+            if (cliParams.revChecker != null) {
+                cliParams.pkixParams.addCertPathChecker(cliParams.revChecker);
+            }
+
+            ManagerFactoryParameters trustParams =
+                    new CertPathTrustManagerParameters(cliParams.pkixParams);
+            tmf.init(trustParams);
+        } else {
+            tmf.init(trustStore);
+        }
+
+        SSLContext sslc = SSLContext.getInstance("TLS");
+        sslc.init(null, tmf.getTrustManagers(), null);
+
+        SSLSocketFactory sslsf = new CustomizedSocketFactory(sslc,
+                cliParams.protocols, cliParams.ciphers);
+        try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket("localhost",
+                serverPort);
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream()) {
+            int numberSent = 80;
+            sslOS.write(numberSent);
+            sslOS.flush();
+            log("Client sent number: " + numberSent);
+            int numberIn = sslIS.read();
+            log("Client received number:" + numberIn);
+        }
+    }
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SSLSocketWithStapling(ClientParameters cliParams,
+            ServerParameters servParams) throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(servParams, true);
+                startClient(cliParams, false);
+            } else {
+                startClient(cliParams, true);
+                startServer(servParams, false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+    }
+
+    /**
+     * Checks a validation failure to see if it failed for the reason we think
+     * it should.  This comes in as an SSLException of some sort, but it
+     * encapsulates a ValidatorException which in turn encapsulates the
+     * CertPathValidatorException we are interested in.
+     *
+     * @param e the exception thrown at the top level
+     * @param reason the underlying CertPathValidatorException BasicReason
+     * we are expecting it to have.
+     *
+     * @return true if the reason matches up, false otherwise.
+     */
+    static boolean checkClientValidationFailure(Exception e,
+            BasicReason reason) {
+        boolean result = false;
+
+        if (e instanceof SSLException) {
+            Throwable valExc = e.getCause();
+            if (valExc instanceof sun.security.validator.ValidatorException) {
+                Throwable cause = valExc.getCause();
+                if (cause instanceof CertPathValidatorException) {
+                    CertPathValidatorException cpve =
+                            (CertPathValidatorException)cause;
+                    if (cpve.getReason() == reason) {
+                        result = true;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    TestResult getResult() {
+        TestResult tr = new TestResult();
+        tr.clientExc = clientException;
+        tr.serverExc = serverException;
+        return tr;
+    }
+
+    void startServer(ServerParameters servParams, boolean newThread)
+            throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide(servParams);
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        e.printStackTrace(System.err);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide(servParams);
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(ClientParameters cliParams, boolean newThread)
+            throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide(cliParams);
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide(cliParams);
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(debug);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(debug);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert an X509Certificate to be displayed
+     *
+     * @return the String output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+
+    /**
+     * Log a message on stdout
+     *
+     * @param message The message to log
+     */
+    private static void log(String message) {
+        if (debug) {
+            System.out.println(message);
+        }
+    }
+
+    // The following two classes are Simple nested class to group a handful
+    // of configuration parameters used before starting a client or server.
+    // We'll just access the data members directly for convenience.
+    static class ClientParameters {
+        boolean enabled = true;
+        PKIXBuilderParameters pkixParams = null;
+        PKIXRevocationChecker revChecker = null;
+        String[] protocols = null;
+        String[] ciphers = null;
+
+        ClientParameters() { }
+    }
+
+    static class ServerParameters {
+        boolean enabled = true;
+        int cacheSize = 256;
+        int cacheLifetime = 3600;
+        int respTimeout = 5000;
+        String respUri = "";
+        boolean respOverride = false;
+        boolean ignoreExts = false;
+        String[] protocols = null;
+        String[] ciphers = null;
+
+        ServerParameters() { }
+    }
+
+    static class CustomizedSocketFactory extends SSLSocketFactory {
+        final SSLContext sslc;
+        final String[] protocols;
+        final String[] cipherSuites;
+
+        CustomizedSocketFactory(SSLContext ctx, String[] prots, String[] suites)
+                throws GeneralSecurityException {
+            super();
+            sslc = (ctx != null) ? ctx : SSLContext.getDefault();
+            protocols = prots;
+            cipherSuites = suites;
+
+            // Create the Trust Manager Factory using the PKIX variant
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        }
+
+        @Override
+        public Socket createSocket(Socket s, String host, int port,
+                boolean autoClose) throws IOException {
+            Socket sock =  sslc.getSocketFactory().createSocket(s, host, port,
+                    autoClose);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress host, int port)
+                throws IOException {
+            Socket sock = sslc.getSocketFactory().createSocket(host, port);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(InetAddress host, int port,
+                InetAddress localAddress, int localPort) throws IOException {
+            Socket sock = sslc.getSocketFactory().createSocket(host, port,
+                    localAddress, localPort);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(String host, int port)
+                throws IOException {
+            Socket sock =  sslc.getSocketFactory().createSocket(host, port);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public Socket createSocket(String host, int port,
+                InetAddress localAddress, int localPort)
+                throws IOException {
+            Socket sock =  sslc.getSocketFactory().createSocket(host, port,
+                    localAddress, localPort);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public String[] getDefaultCipherSuites() {
+            return sslc.getDefaultSSLParameters().getCipherSuites();
+        }
+
+        @Override
+        public String[] getSupportedCipherSuites() {
+            return sslc.getSupportedSSLParameters().getCipherSuites();
+        }
+
+        private void customizeSocket(Socket sock) {
+            if (sock instanceof SSLSocket) {
+                if (protocols != null) {
+                    ((SSLSocket)sock).setEnabledProtocols(protocols);
+                }
+                if (cipherSuites != null) {
+                    ((SSLSocket)sock).setEnabledCipherSuites(cipherSuites);
+                }
+            }
+        }
+    }
+
+    static class CustomizedServerSocketFactory extends SSLServerSocketFactory {
+        final SSLContext sslc;
+        final String[] protocols;
+        final String[] cipherSuites;
+
+        CustomizedServerSocketFactory(SSLContext ctx, String[] prots, String[] suites)
+                throws GeneralSecurityException {
+            super();
+            sslc = (ctx != null) ? ctx : SSLContext.getDefault();
+            protocols = prots;
+            cipherSuites = suites;
+
+            // Create the Trust Manager Factory using the PKIX variant
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        }
+
+        @Override
+        public ServerSocket createServerSocket(int port) throws IOException {
+            ServerSocket sock =
+                    sslc.getServerSocketFactory().createServerSocket(port);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public ServerSocket createServerSocket(int port, int backlog)
+                throws IOException {
+            ServerSocket sock =
+                    sslc.getServerSocketFactory().createServerSocket(port,
+                            backlog);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public ServerSocket createServerSocket(int port, int backlog,
+                InetAddress ifAddress) throws IOException {
+            ServerSocket sock =
+                    sslc.getServerSocketFactory().createServerSocket(port,
+                            backlog, ifAddress);
+            customizeSocket(sock);
+            return sock;
+        }
+
+        @Override
+        public String[] getDefaultCipherSuites() {
+            return sslc.getDefaultSSLParameters().getCipherSuites();
+        }
+
+        @Override
+        public String[] getSupportedCipherSuites() {
+            return sslc.getSupportedSSLParameters().getCipherSuites();
+        }
+
+        private void customizeSocket(ServerSocket sock) {
+            if (sock instanceof SSLServerSocket) {
+                if (protocols != null) {
+                    ((SSLServerSocket)sock).setEnabledProtocols(protocols);
+                }
+                if (cipherSuites != null) {
+                    ((SSLServerSocket)sock).setEnabledCipherSuites(cipherSuites);
+                }
+            }
+        }
+    }
+
+
+    static class TestResult {
+        Exception serverExc = null;
+        Exception clientExc = null;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/Stapling/StapleEnableProps.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8145854 8153829
+ * @summary SSLContextImpl.statusResponseManager should be generated if required
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm StapleEnableProps
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.math.BigInteger;
+import java.security.*;
+import java.nio.*;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+public class StapleEnableProps {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+
+    // These four ByteBuffer references will be used to hang onto ClientHello
+    // messages with and without the status_request[_v2] extensions.  These
+    // will be used in the server-side stapling tests.  There are two sets,
+    // one for 1.2 and earlier versions of the protocol and one for 1.3
+    // and later versions, since the handshake and extension sets differ
+    // between the two sets.
+    private static ByteBuffer cHello12Staple;
+    private static ByteBuffer cHello12NoStaple;
+    private static ByteBuffer cHello13Staple;
+    private static ByteBuffer cHello13NoStaple;
+
+    // The following items are used to set up the keystores.
+    private static final String passwd = "passphrase";
+    private static final String ROOT_ALIAS = "root";
+    private static final String INT_ALIAS = "intermediate";
+    private static final String SSL_ALIAS = "ssl";
+
+    // PKI components we will need for this test
+    private static KeyManagerFactory kmf;
+    private static TrustManagerFactory tmf;
+    private static KeyStore rootKeystore;       // Root CA Keystore
+    private static KeyStore intKeystore;        // Intermediate CA Keystore
+    private static KeyStore serverKeystore;     // SSL Server Keystore
+    private static KeyStore trustStore;         // SSL Client trust store
+    private static SimpleOCSPServer rootOcsp;   // Root CA OCSP Responder
+    private static int rootOcspPort;            // Port for root OCSP
+    private static SimpleOCSPServer intOcsp;    // Intermediate CA OCSP server
+    private static int intOcspPort;             // Port for intermediate OCSP
+
+    // Extra configuration parameters and constants
+    static final String[] TLS13ONLY = new String[] { "TLSv1.3" };
+    static final String[] TLS12MAX =
+            new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
+
+    // A few helpful TLS definitions to make it easier
+    private static final int HELLO_EXT_STATUS_REQ = 5;
+    private static final int HELLO_EXT_STATUS_REQ_V2 = 17;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl:handshake,verbose");
+        }
+
+        // Create the PKI we will use for the test and start the OCSP servers
+        createPKI();
+
+        // Set up the KeyManagerFactory and TrustManagerFactory
+        kmf = KeyManagerFactory.getInstance("PKIX");
+        kmf.init(serverKeystore, passwd.toCharArray());
+        tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(trustStore);
+
+        // Run the client and server property tests
+        testClientProp();
+        testServerProp();
+
+    }
+
+    private static void testClientProp() throws Exception {
+        SSLEngineResult clientResult;
+
+        // Test with the client-side enable property set to true
+        System.out.println("=========================================");
+        System.out.println("Client Test 1: " +
+                "jdk.tls.client.enableStatusRequestExtension = true");
+        System.out.println("Version = TLS 1.2");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "true");
+        SSLContext ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(null, tmf.getTrustManagers(), null);
+        SSLEngine engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        engine.setEnabledProtocols(TLS12MAX);
+        SSLSession session = engine.getSession();
+        ByteBuffer clientOut = ByteBuffer.wrap("I'm a Client".getBytes());
+        ByteBuffer cTOs =
+                ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, true, true);
+        cHello12Staple = cTOs;
+
+        // Test with the property set to false
+        System.out.println("=========================================");
+        System.out.println("Client Test 2: " +
+                "jdk.tls.client.enableStatusRequestExtension = false");
+        System.out.println("Version = TLS 1.2");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "false");
+        SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(null, tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        engine.setEnabledProtocols(TLS12MAX);
+        session = engine.getSession();
+        cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, false, false);
+        cHello12NoStaple = cTOs;
+
+        // Turn the property back on to true and test using TLS 1.3
+        System.out.println("=========================================");
+        System.out.println("Client Test 3: " +
+                "jdk.tls.client.enableStatusRequestExtension = true");
+        System.out.println("Version = TLS 1.3");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "true");
+        ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(null, tmf.getTrustManagers(), null);
+        engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        engine.setEnabledProtocols(TLS13ONLY);
+        session = engine.getSession();
+        cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, true, false);
+        cHello13Staple = cTOs;
+
+        // Turn the property off again and test in a TLS 1.3 handshake
+        System.out.println("=========================================");
+        System.out.println("Client Test 4: " +
+                "jdk.tls.client.enableStatusRequestExtension = false");
+        System.out.println("Version = TLS 1.3");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "false");
+        ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(null, tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        engine.setEnabledProtocols(TLS13ONLY);
+        session = engine.getSession();
+        cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, false, false);
+        cHello13NoStaple = cTOs;
+
+        // A TLS 1.3-capable hello, one that is not strictly limited to
+        // the TLS 1.3 protocol should have both status_request and
+        // status_request_v2
+        System.out.println("=========================================");
+        System.out.println("Client Test 5: " +
+                "jdk.tls.client.enableStatusRequestExtension = true");
+        System.out.println("Version = TLS 1.3 capable [default hello]");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.client.enableStatusRequestExtension",
+                "true");
+        ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(null, tmf.getTrustManagers(), null);
+        engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(true);
+        // Note: Unlike the other tests, there is no explicit protocol setting
+        session = engine.getSession();
+        cTOs = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Create and check the ClientHello message
+        clientResult = engine.wrap(clientOut, cTOs);
+        log("client wrap: ", clientResult);
+        if (clientResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    clientResult.getStatus());
+        }
+        cTOs.flip();
+        System.out.println(dumpHexBytes(cTOs));
+        checkClientHello(cTOs, true, true);
+    }
+
+    private static void testServerProp() throws Exception {
+        SSLEngineResult serverResult;
+        HandshakeStatus hsStat;
+
+        // Test with the server-side enable property set to true
+        System.out.println("=========================================");
+        System.out.println("Server Test 1: " +
+                "jdk.tls.server.enableStatusRequestExtension = true");
+        System.out.println("Version = TLS 1.2");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                "true");
+        SSLContext ctxStaple = SSLContext.getInstance("TLS");
+        ctxStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        SSLEngine engine = ctxStaple.createSSLEngine();
+        engine.setUseClientMode(false);
+        engine.setEnabledProtocols(TLS12MAX);
+        SSLSession session = engine.getSession();
+        ByteBuffer serverOut = ByteBuffer.wrap("I'm a Server".getBytes());
+        ByteBuffer serverIn =
+                ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
+        ByteBuffer sTOc =
+                ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Consume the client hello
+        serverResult = engine.unwrap(cHello12Staple, serverIn);
+        log("server unwrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Server unwrap got status: " +
+                    serverResult.getStatus());
+        } else if (serverResult.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+             throw new SSLException("Server unwrap expected NEED_TASK, got: " +
+                    serverResult.getHandshakeStatus());
+        }
+        runDelegatedTasks(serverResult, engine);
+        if (engine.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+            throw new SSLException("Expected NEED_WRAP, got: " +
+                    engine.getHandshakeStatus());
+        }
+
+        // Generate a TLS record with the ServerHello
+        serverResult = engine.wrap(serverOut, sTOc);
+        log("client wrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    serverResult.getStatus());
+        }
+        sTOc.flip();
+        System.out.println(dumpHexBytes(sTOc));
+        checkServerHello(sTOc, false, true);
+
+        // Flip the client hello so we can reuse it in the next test.
+        cHello12Staple.flip();
+
+        // Test with the server-side enable property set to false
+        System.out.println("=========================================");
+        System.out.println("Server Test 2: " +
+                "jdk.tls.server.enableStatusRequestExtension = false");
+        System.out.println("Version = TLS 1.2");
+        System.out.println("=========================================");
+
+        System.setProperty("jdk.tls.server.enableStatusRequestExtension",
+                "false");
+        SSLContext ctxNoStaple = SSLContext.getInstance("TLS");
+        ctxNoStaple.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        engine = ctxNoStaple.createSSLEngine();
+        engine.setUseClientMode(false);
+        engine.setEnabledProtocols(TLS12MAX);
+        session = engine.getSession();
+        serverIn = ByteBuffer.allocate(session.getApplicationBufferSize() + 50);
+        sTOc = ByteBuffer.allocateDirect(session.getPacketBufferSize());
+
+        // Consume the client hello
+        serverResult = engine.unwrap(cHello12Staple, serverIn);
+        log("server unwrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Server unwrap got status: " +
+                    serverResult.getStatus());
+        } else if (serverResult.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+             throw new SSLException("Server unwrap expected NEED_TASK, got: " +
+                    serverResult.getHandshakeStatus());
+        }
+        runDelegatedTasks(serverResult, engine);
+        if (engine.getHandshakeStatus() !=
+                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+            throw new SSLException("Expected NEED_WRAP, got: " +
+                    engine.getHandshakeStatus());
+        }
+
+        // Generate a TLS record with the ServerHello
+        serverResult = engine.wrap(serverOut, sTOc);
+        log("client wrap: ", serverResult);
+        if (serverResult.getStatus() != SSLEngineResult.Status.OK) {
+            throw new SSLException("Client wrap got status: " +
+                    serverResult.getStatus());
+        }
+        sTOc.flip();
+        System.out.println(dumpHexBytes(sTOc));
+        checkServerHello(sTOc, false, false);
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+
+    /**
+     * Dump a ByteBuffer as a hexdump to stdout.  The dumping routine will
+     * start at the current position of the buffer and run to its limit.
+     * After completing the dump, the position will be returned to its
+     * starting point.
+     *
+     * @param data the ByteBuffer to dump to stdout.
+     *
+     * @return the hexdump of the byte array.
+     */
+    private static String dumpHexBytes(ByteBuffer data) {
+        StringBuilder sb = new StringBuilder();
+        if (data != null) {
+            int i = 0;
+            data.mark();
+            while (data.hasRemaining()) {
+                if (i % 16 == 0 && i != 0) {
+                    sb.append("\n");
+                }
+                sb.append(String.format("%02X ", data.get()));
+                i++;
+            }
+            data.reset();
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Tests the ClientHello for the presence (or not) of the status_request
+     * and status_request_v2 hello extensions.  It is assumed that the provided
+     * ByteBuffer has its position set at the first byte of the TLS record
+     * containing the ClientHello and contains the entire hello message.  Upon
+     * successful completion of this method the ByteBuffer will have its
+     * position reset to the initial offset in the buffer.  If an exception is
+     * thrown the position at the time of the exception will be preserved.
+     *
+     * @param data the ByteBuffer containing the ClientHello bytes
+     * @param statReqPresent true if the status_request hello extension should
+     * be present.
+     * @param statReqV2Present true if the status_request_v2 hello extension
+     * should be present.
+     *
+     * @throws SSLException if the presence or lack of either the
+     * status_request or status_request_v2 extensions is inconsistent with
+     * the expected settings in the statReqPresent or statReqV2Present
+     * parameters.
+     */
+    private static void checkClientHello(ByteBuffer data,
+            boolean statReqPresent, boolean statReqV2Present)
+            throws SSLException {
+        boolean hasV1 = false;
+        boolean hasV2 = false;
+        Objects.requireNonNull(data);
+        data.mark();
+
+        // Process the TLS record header
+        int type = Byte.toUnsignedInt(data.get());
+        int ver_major = Byte.toUnsignedInt(data.get());
+        int ver_minor = Byte.toUnsignedInt(data.get());
+        int recLen = Short.toUnsignedInt(data.getShort());
+
+        // Simple sanity checks
+        if (type != 22) {
+            throw new SSLException("Not a handshake: Type = " + type);
+        } else if (recLen > data.remaining()) {
+            throw new SSLException("Incomplete record in buffer: " +
+                    "Record length = " + recLen + ", Remaining = " +
+                    data.remaining());
+        }
+
+        // Grab the handshake message header.
+        int msgHdr = data.getInt();
+        int msgType = (msgHdr >> 24) & 0x000000FF;
+        int msgLen = msgHdr & 0x00FFFFFF;
+
+        // More simple sanity checks
+        if (msgType != 1) {
+            throw new SSLException("Not a ClientHello: Type = " + msgType);
+        }
+
+        // Skip over the protocol version and client random
+        data.position(data.position() + 34);
+
+        // Jump past the session ID (if there is one)
+        int sessLen = Byte.toUnsignedInt(data.get());
+        if (sessLen != 0) {
+            data.position(data.position() + sessLen);
+        }
+
+        // Jump past the cipher suites
+        int csLen = Short.toUnsignedInt(data.getShort());
+        if (csLen != 0) {
+            data.position(data.position() + csLen);
+        }
+
+        // ...and the compression
+        int compLen = Byte.toUnsignedInt(data.get());
+        if (compLen != 0) {
+            data.position(data.position() + compLen);
+        }
+
+        // Now for the fun part.  Go through the extensions and look
+        // for the two status request exts.
+        int extsLen = Short.toUnsignedInt(data.getShort());
+        while (data.hasRemaining()) {
+            int extType = Short.toUnsignedInt(data.getShort());
+            int extLen = Short.toUnsignedInt(data.getShort());
+            hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
+            hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
+            data.position(data.position() + extLen);
+        }
+
+        if (hasV1 != statReqPresent) {
+            throw new SSLException("The status_request extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqPresent + ", actual = " + hasV1);
+        } else if (hasV2 != statReqV2Present) {
+            throw new SSLException("The status_request_v2 extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqV2Present + ", actual = " + hasV2);
+        }
+
+        // We should be at the end of the ClientHello
+        data.reset();
+    }
+
+    /**
+     * Tests the ServerHello for the presence (or not) of the status_request
+     * or status_request_v2 hello extension.  It is assumed that the provided
+     * ByteBuffer has its position set at the first byte of the TLS record
+     * containing the ServerHello and contains the entire hello message.  Upon
+     * successful completion of this method the ByteBuffer will have its
+     * position reset to the initial offset in the buffer.  If an exception is
+     * thrown the position at the time of the exception will be preserved.
+     *
+     * @param statReqPresent true if the status_request hello extension should
+     * be present.
+     * @param statReqV2Present true if the status_request_v2 hello extension
+     * should be present.
+     *
+     * @throws SSLException if the presence or lack of either the
+     * status_request or status_request_v2 extensions is inconsistent with
+     * the expected settings in the statReqPresent or statReqV2Present
+     * parameters.
+     */
+    private static void checkServerHello(ByteBuffer data,
+            boolean statReqPresent, boolean statReqV2Present)
+            throws SSLException {
+        boolean hasV1 = false;
+        boolean hasV2 = false;
+        Objects.requireNonNull(data);
+        int startPos = data.position();
+        data.mark();
+
+        // Process the TLS record header
+        int type = Byte.toUnsignedInt(data.get());
+        int ver_major = Byte.toUnsignedInt(data.get());
+        int ver_minor = Byte.toUnsignedInt(data.get());
+        int recLen = Short.toUnsignedInt(data.getShort());
+
+        // Simple sanity checks
+        if (type != 22) {
+            throw new SSLException("Not a handshake: Type = " + type);
+        } else if (recLen > data.remaining()) {
+            throw new SSLException("Incomplete record in buffer: " +
+                    "Record length = " + recLen + ", Remaining = " +
+                    data.remaining());
+        }
+
+        // Grab the handshake message header.
+        int msgHdr = data.getInt();
+        int msgType = (msgHdr >> 24) & 0x000000FF;
+        int msgLen = msgHdr & 0x00FFFFFF;
+
+        // More simple sanity checks
+        if (msgType != 2) {
+            throw new SSLException("Not a ServerHello: Type = " + msgType);
+        }
+
+        // Skip over the protocol version and server random
+        data.position(data.position() + 34);
+
+        // Jump past the session ID
+        int sessLen = Byte.toUnsignedInt(data.get());
+        if (sessLen != 0) {
+            data.position(data.position() + sessLen);
+        }
+
+        // Skip the cipher suite and compression method
+        data.position(data.position() + 3);
+
+        // Go through the extensions and look for the request extension
+        // expected by the caller.
+        int extsLen = Short.toUnsignedInt(data.getShort());
+        while (data.position() < recLen + startPos + 5) {
+            int extType = Short.toUnsignedInt(data.getShort());
+            int extLen = Short.toUnsignedInt(data.getShort());
+            hasV1 |= (extType == HELLO_EXT_STATUS_REQ);
+            hasV2 |= (extType == HELLO_EXT_STATUS_REQ_V2);
+            data.position(data.position() + extLen);
+        }
+
+        if (hasV1 != statReqPresent) {
+            throw new SSLException("The status_request extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqPresent + ", actual = " + hasV1);
+        } else if (hasV2 != statReqV2Present) {
+            throw new SSLException("The status_request_v2 extension is " +
+                    "inconsistent with the expected result: expected = " +
+                    statReqV2Present + ", actual = " + hasV2);
+        }
+
+        // Reset the position to the initial spot at the start of this method.
+        data.reset();
+    }
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(logging);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(logging);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        java.security.cert.Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert an X509Certificate to be displayed
+     *
+     * @return the String output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/CipherTestUtils.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,682 @@
+/*
+ * Copyright (c) 2010, 2016, 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.
+ *
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.List;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Test that all ciphersuites work in all versions and all client authentication
+ * types. The way this is setup the server is stateless and all checking is done
+ * on the client side.
+ */
+
+public class CipherTestUtils {
+
+    public static final int TIMEOUT = 20 * 1000;
+    public static final SecureRandom secureRandom = new SecureRandom();
+    public static char[] PASSWORD = "passphrase".toCharArray();
+    private static final List<TestParameters> TESTS = new ArrayList<>(3);
+    private static final List<Exception> EXCEPTIONS
+            = Collections.synchronizedList(new ArrayList<>(1));
+
+    private static final String CLIENT_PUBLIC_KEY
+        = "-----BEGIN CERTIFICATE-----\n"
+        + "MIICtTCCAh4CCQDkYJ46DMcGRjANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMC\n"
+        + "VVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MR8wHQYDVQQK\n"
+        + "DBZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMSYwJAYDVQQLDB1TdW4gTWljcm9zeXN0\n"
+        + "ZW1zIExhYm9yYXRvcmllczEfMB0GA1UEAwwWVGVzdCBDQSAoMTAyNCBiaXQgUlNB\n"
+        + "KTAeFw0wOTA0MjcwNDA0MDhaFw0xMzA2MDUwNDA0MDhaMIGgMQswCQYDVQQGEwJV\n"
+        + "UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAdBgNVBAoM\n"
+        + "FlN1biBNaWNyb3N5c3RlbXMsIEluYy4xJjAkBgNVBAsMHVN1biBNaWNyb3N5c3Rl\n"
+        + "bXMgTGFib3JhdG9yaWVzMSMwIQYDVQQDDBpUZXN0IENsaWVudCAoMTAyNCBiaXQg\n"
+        + "UlNBKTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAm5rwjmhO7Nwd5GWs+KvQ\n"
+        + "UnDiqpRDvRriOUFdF0rCI2Op24C+iwUMDGxPsgP7VkUpOdJhw3c72aP0CAWcZ5dN\n"
+        + "UCW7WVDAxnogCahLCir1jjoGdEjiNGOy0L9sypsM9UvBzJN8uvXsxsTZX4Z88cKU\n"
+        + "G7RUvN8LQ88zDljk5zr3c2MCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA7LUDrzHln\n"
+        + "EXuGmwZeeroACB6DVtkClMskF/Pj5GnTxoeNN9DggycX/eOeIDKRloHuMpBeZPJH\n"
+        + "NUwFu4LB6HBDeldQD9iRp8zD/fPakOdN+1Gk5hciIZZJ5hQmeCl7Va2Gr64vUqZG\n"
+        + "MkVU755t+7ByLgzWuhPhhsX9QCuPR5FjvQ==\n"
+        + "-----END CERTIFICATE-----";
+
+    private static final String CLIENT_PRIVATE_KEY
+        = "-----BEGIN PRIVATE KEY-----\n"
+        + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJua8I5oTuzcHeRl\n"
+        + "rPir0FJw4qqUQ70a4jlBXRdKwiNjqduAvosFDAxsT7ID+1ZFKTnSYcN3O9mj9AgF\n"
+        + "nGeXTVAlu1lQwMZ6IAmoSwoq9Y46BnRI4jRjstC/bMqbDPVLwcyTfLr17MbE2V+G\n"
+        + "fPHClBu0VLzfC0PPMw5Y5Oc693NjAgMBAAECgYA5w73zj8Nk6J3sMNaShe3S/PcY\n"
+        + "TewLopRCnwI46FbDnnbq9pNFtnzvi7HWKuY983THc1M5peTA+b1Y0QRr7F4Vg4x9\n"
+        + "9UM0B/tZcIIcJJ3LS+9fXKCbYLQWq5F05JqeZu+i+QLmJFO5+2p7laeQ4oQfW7QE\n"
+        + "YR4u2mSaLe0SsqHvOQJBAMhgcye9C6pJO0eo2/VtRxAXI7zxNAIjHwKo1cva7bhu\n"
+        + "GdrMaEAJBAsMJ1GEk7/WDI+3KEbTjQdfIJuAvOR4FXUCQQDGzNn/tl2k93v/ugyM\n"
+        + "/tBhCKDipYDIbyJMoG2AOtOGmCsiGo5L7idO4OAcm/QiHBQMXjFIVgTUcH8MhGj4\n"
+        + "blJ3AkA5fUqsxRV6tuYWKkFpif/QgwMS65VDY7Y6+hvVECwSNSyf1PO4I54QWV1S\n"
+        + "ixok+RHDjgY1Q+77hXSCiQ4o8rcdAkBHvjfR+5sx5IpgUGElJPRIgFenU3j1XH3x\n"
+        + "T1gVFaWuhg3S4eiGaGzRH4BhcrqY8K8fg4Kfi0N08yA2gTZsqUujAkEAjuNPTuKx\n"
+        + "ti0LXI09kbGUqOpRMm1zW5TD6LFeEaUN6oxrSZI2YUvu7VyotAqsxX5O0u0f3VQw\n"
+        + "ySF0Q1oZ6qu7cg==\n"
+        + "-----END PRIVATE KEY-----";
+    private static final String SERVER_PUBLIC_KEY
+        = "-----BEGIN CERTIFICATE-----\n"
+        + "MIICtTCCAh4CCQDkYJ46DMcGRTANBgkqhkiG9w0BAQUFADCBnDELMAkGA1UEBhMC\n"
+        + "VVMxCzAJBgNVBAgMAkNBMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MR8wHQYDVQQK\n"
+        + "DBZTdW4gTWljcm9zeXN0ZW1zLCBJbmMuMSYwJAYDVQQLDB1TdW4gTWljcm9zeXN0\n"
+        + "ZW1zIExhYm9yYXRvcmllczEfMB0GA1UEAwwWVGVzdCBDQSAoMTAyNCBiaXQgUlNB\n"
+        + "KTAeFw0wOTA0MjcwNDA0MDhaFw0xMzA2MDUwNDA0MDhaMIGgMQswCQYDVQQGEwJV\n"
+        + "UzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAdBgNVBAoM\n"
+        + "FlN1biBNaWNyb3N5c3RlbXMsIEluYy4xJjAkBgNVBAsMHVN1biBNaWNyb3N5c3Rl\n"
+        + "bXMgTGFib3JhdG9yaWVzMSMwIQYDVQQDDBpUZXN0IFNlcnZlciAoMTAyNCBiaXQg\n"
+        + "UlNBKTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArsHHeZ1O67yuxQKDSAOC\n"
+        + "Xm271ViwBrXkxe5cvhG8MCCem6Z3XeZ/m6c2ucRwLaQxnmG1m0G6/OYaUXTivjcG\n"
+        + "/K4bc1I+yjghAWQNLBtsOiP9w0LKibg3TSDehpeuuz/lmB5A4HMqQr8KkY4K7peD\n"
+        + "1QkJ2Dn3zhbwQ/0d8f5CCbkCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBOd8XojEnu\n"
+        + "eTUHBwqfmnvRQvbICFDNbbL4KuX/JNPSy1WMGAEbNCTLZ+5yP69js8aUYqAk5vVf\n"
+        + "dWRLU3MDiEzW7zxE1ubuKWjVuyGbG8Me0G01Hw+evBcZqB64Fz3OFISVfQh7MqE/\n"
+        + "O0AeakRMH350FRLNl4o6KBSXmF/AADfqQQ==\n"
+        + "-----END CERTIFICATE-----";
+
+    private static final String SERVER_PRIVATE_KEY
+        = "-----BEGIN PRIVATE KEY-----\n"
+        + "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAK7Bx3mdTuu8rsUC\n"
+        + "g0gDgl5tu9VYsAa15MXuXL4RvDAgnpumd13mf5unNrnEcC2kMZ5htZtBuvzmGlF0\n"
+        + "4r43BvyuG3NSPso4IQFkDSwbbDoj/cNCyom4N00g3oaXrrs/5ZgeQOBzKkK/CpGO\n"
+        + "Cu6Xg9UJCdg5984W8EP9HfH+Qgm5AgMBAAECgYAXUv+3qJo+9mjxHHu/IdDFn6nB\n"
+        + "ONwNmTtWe5DfQWi3l7LznU0zOC9x6+hu9NvwC4kf1XSyqxw04tVCZ/JXZurEmEBz\n"
+        + "YtcQ5idRQDkKYXEDOeVUfvtHO6xilzrhPKxxd0GG/sei2pozikkqnYF3OcP0qL+a\n"
+        + "3nWixZQBRoF2nIRLcQJBAN97TJBr0XTRmE7OCKLUy1+ws7vZB9uQ2efHMsgwOpsY\n"
+        + "3cEW5qd95hrxLU72sBeu9loHQgBrT2Q3OAxnsPXmgO0CQQDIL3u9kS/O3Ukx+n1H\n"
+        + "JdPFQCRxrDm/vtJpQEmq+mLqxxnxCFRIYQ2ieAPokBxWeMDtdWJGD3VxhahjPfZm\n"
+        + "5K59AkEAuDVl0tVMfUIWjT5/F9jXGjUIsZofQ/iN5OLpFOHMLPO+Nd6umPjJpwON\n"
+        + "GT11wM/S+DprSPUrJ6vsYy1FTCuHsQJBAMXtnO07xgdE6AAQaRmVnyMiXmY+IQMj\n"
+        + "CyuhsrToyDDWFyIoWB0QSMjg3QxuoHYnAqpGK5qV4ksSGgG13BCz/okCQQCRHTgn\n"
+        + "DuFG2f7GYLFjI4NaTEzHGp+J9LiNYY1kYYLonpwAC3Z5hzJVanYT3/g23AUZ/fdF\n"
+        + "v5PDIViuPo5ZB1eD\n"
+        + "-----END PRIVATE KEY-----";
+
+    private static final String CA_PUBLIC_KEY
+        = "-----BEGIN CERTIFICATE-----\n"
+        + "MIIDCDCCAnGgAwIBAgIJAIYlGfwNBY6NMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD\n"
+        + "VQQGEwJVUzELMAkGA1UECAwCQ0ExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxHzAd\n"
+        + "BgNVBAoMFlN1biBNaWNyb3N5c3RlbXMsIEluYy4xJjAkBgNVBAsMHVN1biBNaWNy\n"
+        + "b3N5c3RlbXMgTGFib3JhdG9yaWVzMR8wHQYDVQQDDBZUZXN0IENBICgxMDI0IGJp\n"
+        + "dCBSU0EpMB4XDTA5MDQyNzA0MDQwOFoXDTEzMDYwNTA0MDQwOFowgZwxCzAJBgNV\n"
+        + "BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEfMB0G\n"
+        + "A1UECgwWU3VuIE1pY3Jvc3lzdGVtcywgSW5jLjEmMCQGA1UECwwdU3VuIE1pY3Jv\n"
+        + "c3lzdGVtcyBMYWJvcmF0b3JpZXMxHzAdBgNVBAMMFlRlc3QgQ0EgKDEwMjQgYml0\n"
+        + "IFJTQSkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOK4DJxxb0XX6MJ1CVjp\n"
+        + "9Gmr/Ua8MS12R58F9lDpSKuq8cFexA4W7OdZ4jtbKv0tRHX5YxmbnXedwS+gdcOA\n"
+        + "GRgXMoeXlgTFGpdL+TR8xKIlMGRSjnR7MpR2tRyIYI2p+UTEiD6LTlIm5Wh4z1q8\n"
+        + "LYbxyMVD1XNNNymvPM44OjsBAgMBAAGjUDBOMB0GA1UdDgQWBBT27BLUflmfdtbi\n"
+        + "WTgjwWnoxop2MTAfBgNVHSMEGDAWgBT27BLUflmfdtbiWTgjwWnoxop2MTAMBgNV\n"
+        + "HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAEQELNzhZpjnSgigd+QJ6I/3CPDo\n"
+        + "SDkMLdP1BHlT/DkMIZvABm+M09ePNlWiLYCNCsL9nWmX0gw0rFDKsTklZyKTUzaM\n"
+        + "oy/AZCrAaoIc6SO5m1xE1RMyVxd/Y/kg6cbfWxxCJFlMeU5rsSdC97HTE/lDyuoh\n"
+        + "BmlOBB7SdR+1ScjA\n"
+        + "-----END CERTIFICATE-----";
+
+    private static final String CA_PRIVATE_KEY
+        = "-----BEGIN PRIVATE KEY-----\n"
+        + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOK4DJxxb0XX6MJ1\n"
+        + "CVjp9Gmr/Ua8MS12R58F9lDpSKuq8cFexA4W7OdZ4jtbKv0tRHX5YxmbnXedwS+g\n"
+        + "dcOAGRgXMoeXlgTFGpdL+TR8xKIlMGRSjnR7MpR2tRyIYI2p+UTEiD6LTlIm5Wh4\n"
+        + "z1q8LYbxyMVD1XNNNymvPM44OjsBAgMBAAECgYEApmMOlk3FrQtsvjGof4GLp3Xa\n"
+        + "tmvs54FzxKhagj0C4UHelNyYpAJ9MLjNiGQ7I31yTeaNrUCAi0XSfsKTSrwbLSnJ\n"
+        + "qsUPKMBrnzcWrOyui2+cupHZXaTlNeYB97teLJYpa6Ql9CZLoTHoim1+//s7diBh\n"
+        + "03Vls+M6Poi5PMvv59UCQQD+k/BiokmbBgWHfBY5cZSlx3Z4VTwSHJmHDTO3Tjso\n"
+        + "EVErXUSVvqD/KHX6eM4VPM8lySV5djWV8lDsESCWMtiLAkEA4/xFNsiOLMQpxW/O\n"
+        + "bt2tukxJkAxldD4lPoFZR+zbXtMtt8OjERtX2wD+nj6h7jfIeSyVuBEcBN8Uj8xe\n"
+        + "kgfgIwJAPbKG4LCqHAsCjgpRrIxNVTwZByLJEy6hOqzFathn19cSj+rjs1Lm28/n\n"
+        + "f9OFRnpdTbAJB/3REM0QNZYVCrG57wJBAN0KuTytZJNouaswhPCew5Kt5mDgc/kp\n"
+        + "S8j3dk2zCto8W8Ygy1iJrzuqEjPxO+UQdrFtlde51vWuKGxnVIW3VwsCQEldqk7r\n"
+        + "8y7PgquPP+k3L0OXno5wGBrPcW1+U0mhIZGnwSzE4SPX2ddqUSEUA/Av4RjAckL/\n"
+        + "fpqmCkpTanyYW9U=\n"
+        + "-----END PRIVATE KEY-----";
+
+    private final SSLSocketFactory factory;
+    private final X509ExtendedKeyManager clientKeyManager;
+    private final X509ExtendedKeyManager serverKeyManager;
+    private final X509TrustManager clientTrustManager;
+    private final X509TrustManager serverTrustManager;
+
+    static abstract class Server implements Runnable, AutoCloseable {
+
+        final CipherTestUtils cipherTest;
+
+        Server(CipherTestUtils cipherTest) throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        @Override
+        public abstract void run();
+
+        abstract int getPort();
+
+        void handleRequest(InputStream in, OutputStream out)
+                throws IOException {
+            boolean newline = false;
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                int ch = in.read();
+                if (ch < 0) {
+                    throw new EOFException();
+                }
+                sb.append((char) ch);
+                if (ch == '\r') {
+                    // empty
+                } else if (ch == '\n') {
+                    if (newline) {
+                        // 2nd newline in a row, end of request
+                        break;
+                    }
+                    newline = true;
+                } else {
+                    newline = false;
+                }
+            }
+            String request = sb.toString();
+            if (request.startsWith("GET / HTTP/1.") == false) {
+                throw new IOException("Invalid request: " + request);
+            }
+            out.write("HTTP/1.0 200 OK\r\n\r\n".getBytes());
+            out.write("Tested Scenario: ".getBytes());
+            TestParameters tp = (TestParameters) CipherTestUtils.TESTS.get(0);
+            out.write(tp.toString().getBytes());
+            out.write(" Test PASSED.".getBytes());
+        }
+    }
+
+    public static class TestParameters {
+
+        final String cipherSuite;
+        final String protocol;
+        final String clientAuth;
+
+        TestParameters(String cipherSuite, String protocol, String clientAuth) {
+            this.cipherSuite = cipherSuite;
+            this.protocol = protocol;
+            this.clientAuth = clientAuth;
+        }
+
+        boolean isEnabled() {
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            String s = cipherSuite + " in " + protocol + " mode";
+            if (clientAuth != null) {
+                s += " with " + clientAuth + " client authentication";
+            }
+            return s;
+        }
+    }
+
+    private static volatile CipherTestUtils instance = null;
+
+    public static CipherTestUtils getInstance() throws Exception {
+        if (instance == null) {
+            synchronized (CipherTestUtils.class) {
+                if (instance == null) {
+                    instance = new CipherTestUtils();
+                }
+            }
+        }
+        return instance;
+    }
+
+    public static void setTestedArguments(String protocol, String ciphersuite) {
+        ciphersuite = ciphersuite.trim();
+        TestParameters params = new TestParameters(ciphersuite, protocol, null);
+        TESTS.add(params);
+    }
+
+    public X509ExtendedKeyManager getClientKeyManager() {
+        return clientKeyManager;
+    }
+
+    public X509TrustManager getClientTrustManager() {
+        return clientTrustManager;
+    }
+
+    public X509ExtendedKeyManager getServerKeyManager() {
+        return serverKeyManager;
+    }
+
+    public X509TrustManager getServerTrustManager() {
+        return serverTrustManager;
+    }
+
+    public static void addFailure(Exception e) {
+        EXCEPTIONS.add(e);
+    }
+
+    private CipherTestUtils() throws Exception {
+        factory = (SSLSocketFactory) SSLSocketFactory.getDefault();
+        KeyStore serverKeyStore = createServerKeyStore(SERVER_PUBLIC_KEY,
+                SERVER_PRIVATE_KEY);
+        KeyStore serverTrustStore = createServerKeyStore(CA_PUBLIC_KEY,
+                CA_PRIVATE_KEY);
+
+        if (serverKeyStore != null) {
+            KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(
+                            KeyManagerFactory.getDefaultAlgorithm());
+            keyFactory.init(serverKeyStore, PASSWORD);
+            serverKeyManager = (X509ExtendedKeyManager)
+                    keyFactory.getKeyManagers()[0];
+        } else {
+            serverKeyManager = null;
+        }
+        serverTrustManager = serverTrustStore != null
+                ? new AlwaysTrustManager(serverTrustStore) : null;
+
+        KeyStore clientKeyStore, clientTrustStore;
+        clientTrustStore = serverTrustStore;
+        clientKeyStore =
+                createServerKeyStore(CLIENT_PUBLIC_KEY,CLIENT_PRIVATE_KEY);
+        if (clientKeyStore != null) {
+            KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(
+                            KeyManagerFactory.getDefaultAlgorithm());
+            keyFactory.init(clientKeyStore, PASSWORD);
+            clientKeyManager = (X509ExtendedKeyManager)
+                    keyFactory.getKeyManagers()[0];
+        } else {
+            clientKeyManager = null;
+        }
+        clientTrustManager = (clientTrustStore != null)
+                ? new AlwaysTrustManager(clientTrustStore) : null;
+    }
+
+    void checkResult(String exception) throws Exception {
+        if (EXCEPTIONS.size() >= 1) {
+            Exception actualException = EXCEPTIONS.get(0);
+            if (exception == null) {
+                throw new RuntimeException("FAILED: got unexpected exception: "
+                        + actualException);
+            }
+            if (!exception.equals(actualException.getClass().getName())) {
+                throw new RuntimeException("FAILED: got unexpected exception: "
+                        + actualException);
+            }
+
+            System.out.println("PASSED: got expected exception: "
+                    + actualException);
+        } else {
+            if (exception != null) {
+                throw new RuntimeException("FAILED: " + exception
+                        + " was expected");
+            }
+            System.out.println("PASSED");
+        }
+    }
+
+    SSLSocketFactory getFactory() {
+        return factory;
+    }
+
+    static abstract class Client implements Runnable {
+
+        final CipherTestUtils cipherTest;
+        TestParameters testedParams;
+
+        Client(CipherTestUtils cipherTest) throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        Client(CipherTestUtils cipherTest, String testedCipherSuite)
+                throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        @Override
+        public final void run() {
+
+            TESTS.stream().map((params) -> {
+                if (!params.isEnabled()) {
+                    System.out.println("Skipping disabled test " + params);
+                }
+                return params;
+            }).forEach((params) -> {
+                try {
+                    System.out.println("Testing " + params);
+                    runTest(params);
+                    System.out.println("Passed " + params);
+                } catch (Exception e) {
+                    CipherTestUtils.addFailure(e);
+                    System.out.println("** Failed " + params
+                            + "**, got exception:");
+                    e.printStackTrace(System.out);
+                }
+            });
+        }
+
+        abstract void runTest(TestParameters params) throws Exception;
+
+        void sendRequest(InputStream in, OutputStream out) throws IOException {
+            out.write("GET / HTTP/1.0\r\n\r\n".getBytes());
+            out.flush();
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                int ch = in.read();
+                if (ch < 0) {
+                    break;
+                }
+                sb.append((char) ch);
+            }
+            String response = sb.toString();
+            if (response.startsWith("HTTP/1.0 200 ") == false) {
+                throw new IOException("Invalid response: " + response);
+            } else {
+                System.out.println();
+                System.out.println("--- Response --- ");
+                System.out.println(response);
+                System.out.println("---------------- ");
+            }
+        }
+    }
+
+    public static void printStringArray(String[] stringArray) {
+        System.out.println(Arrays.toString(stringArray));
+        System.out.println();
+    }
+
+    public static void printInfo(SSLServerSocket socket) {
+        System.out.println();
+        System.out.println("--- SSL ServerSocket Info ---");
+        System.out.print("SupportedProtocols    : ");
+        printStringArray(socket.getSupportedProtocols());
+        System.out.print("SupportedCipherSuites : ");
+        printStringArray(socket.getSupportedCipherSuites());
+        System.out.print("EnabledProtocols      : ");
+        printStringArray(socket.getEnabledProtocols());
+        System.out.print("EnabledCipherSuites   : ");
+        String[] supportedCipherSuites = socket.getEnabledCipherSuites();
+        Arrays.sort(supportedCipherSuites);
+        printStringArray(supportedCipherSuites);
+        System.out.println("NeedClientAuth        : "
+                + socket.getNeedClientAuth());
+        System.out.println("WantClientAuth        : "
+                + socket.getWantClientAuth());
+        System.out.println("-----------------------");
+    }
+
+    public static void printInfo(SSLSocket socket) {
+        System.out.println();
+        System.out.println("--- SSL Socket Info ---");
+        System.out.print(" SupportedProtocols    : ");
+        printStringArray(socket.getSupportedProtocols());
+        System.out.println(" EnabledProtocols      : "
+                + socket.getEnabledProtocols()[0]);
+        System.out.print(" SupportedCipherSuites : ");
+        String[] supportedCipherSuites = socket.getEnabledCipherSuites();
+        Arrays.sort(supportedCipherSuites);
+        printStringArray(supportedCipherSuites);
+        System.out.println(" EnabledCipherSuites   : "
+                + socket.getEnabledCipherSuites()[0]);
+        System.out.println(" NeedClientAuth        : "
+                + socket.getNeedClientAuth());
+        System.out.println(" WantClientAuth        : "
+                + socket.getWantClientAuth());
+        System.out.println("-----------------------");
+    }
+
+    private static KeyStore createServerKeyStore(String publicKey,
+            String keySpecStr) throws KeyStoreException, IOException,
+            NoSuchAlgorithmException, CertificateException,
+            InvalidKeySpecException {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+        if (publicKey == null || keySpecStr == null) {
+            throw new IllegalArgumentException("publicKey or "
+                    + "keySpecStr cannot be null");
+        }
+        String strippedPrivateKey = keySpecStr.substring(
+                keySpecStr.indexOf("\n"), keySpecStr.lastIndexOf("\n"));
+
+        // generate the private key.
+        PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                Base64.getMimeDecoder().decode(strippedPrivateKey));
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKey priKey
+                = (RSAPrivateKey) kf.generatePrivate(priKeySpec);
+
+        // generate certificate chain
+        try (InputStream is = new ByteArrayInputStream(publicKey.getBytes())) {
+            // generate certificate from cert string
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            Certificate keyCert = cf.generateCertificate(is);
+            Certificate[] chain = {keyCert};
+            ks.setKeyEntry("TestEntry", priKey, PASSWORD, chain);
+        }
+
+        return ks;
+    }
+
+    public static Server mainServer(PeerFactory peerFactory,
+            String expectedException) throws Exception {
+
+        setTestedArguments(peerFactory.getTestedProtocol(),
+                peerFactory.getTestedCipher());
+
+        System.out.print(
+                " Initializing test '" + peerFactory.getName() + "'...");
+        secureRandom.nextInt();
+
+        CipherTestUtils cipherTest = CipherTestUtils.getInstance();
+        Server srv = peerFactory.newServer(cipherTest, PeerFactory.FREE_PORT);
+        Thread serverThread = new Thread(srv, "Server");
+        serverThread.start();
+
+        return srv;
+    }
+
+    public static void mainClient(PeerFactory peerFactory, int port,
+            String expectedException) throws Exception {
+
+        long time = System.currentTimeMillis();
+        setTestedArguments(peerFactory.getTestedProtocol(),
+                peerFactory.getTestedCipher());
+
+        System.out.print(
+                " Initializing test '" + peerFactory.getName() + "'...");
+        secureRandom.nextInt();
+
+        CipherTestUtils cipherTest = CipherTestUtils.getInstance();
+        peerFactory.newClient(cipherTest, port).run();
+        cipherTest.checkResult(expectedException);
+
+        time = System.currentTimeMillis() - time;
+        System.out.println("Elapsed time " + time);
+    }
+
+    public static abstract class PeerFactory {
+
+        public static final int FREE_PORT = 0;
+
+        abstract String getName();
+
+        abstract String getTestedProtocol();
+
+        abstract String getTestedCipher();
+
+        abstract Client newClient(CipherTestUtils cipherTest, int testPort)
+                throws Exception;
+
+        abstract Server newServer(CipherTestUtils cipherTest, int testPort)
+                throws Exception;
+
+        boolean isSupported(String cipherSuite) {
+            return true;
+        }
+    }
+}
+
+class AlwaysTrustManager implements X509TrustManager {
+
+    X509TrustManager trustManager;
+
+    public AlwaysTrustManager(KeyStore keyStore)
+            throws NoSuchAlgorithmException, KeyStoreException {
+
+        TrustManagerFactory tmf
+                = TrustManagerFactory.getInstance(TrustManagerFactory.
+                        getDefaultAlgorithm());
+        tmf.init(keyStore);
+
+        TrustManager tms[] = tmf.getTrustManagers();
+        for (TrustManager tm : tms) {
+            trustManager = (X509TrustManager) tm;
+            return;
+        }
+
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        try {
+            trustManager.checkClientTrusted(chain, authType);
+        } catch (CertificateException excep) {
+            System.out.println("ERROR in client trust manager: " + excep);
+        }
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        try {
+            trustManager.checkServerTrusted(chain, authType);
+        } catch (CertificateException excep) {
+            System.out.println("ERROR in server trust manager: " + excep);
+        }
+    }
+
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        return trustManager.getAcceptedIssuers();
+    }
+}
+
+class MyX509KeyManager extends X509ExtendedKeyManager {
+
+    private final X509ExtendedKeyManager keyManager;
+    private String authType;
+
+    MyX509KeyManager(X509ExtendedKeyManager keyManager) {
+        this.keyManager = keyManager;
+    }
+
+    void setAuthType(String authType) {
+        this.authType = "ECDSA".equals(authType) ? "EC" : authType;
+    }
+
+    @Override
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.getClientAliases(authType, issuers);
+    }
+
+    @Override
+    public String chooseClientAlias(String[] keyType, Principal[] issuers,
+            Socket socket) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.chooseClientAlias(new String[]{authType},
+                issuers, socket);
+    }
+
+    @Override
+    public String chooseEngineClientAlias(String[] keyType,
+            Principal[] issuers, SSLEngine engine) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.chooseEngineClientAlias(new String[]{authType},
+                issuers, engine);
+    }
+
+    @Override
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    @Override
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+            Socket socket) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    @Override
+    public String chooseEngineServerAlias(String keyType, Principal[] issuers,
+            SSLEngine engine) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    @Override
+    public X509Certificate[] getCertificateChain(String alias) {
+        return keyManager.getCertificateChain(alias);
+    }
+
+    @Override
+    public PrivateKey getPrivateKey(String alias) {
+        return keyManager.getPrivateKey(alias);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/JSSEClient.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010, 2016, 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.
+ *
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+class JSSEClient extends CipherTestUtils.Client {
+
+    private static final String DEFAULT = "DEFAULT";
+    private static final String TLS = "TLS";
+
+    private final SSLContext context;
+    private final MyX509KeyManager keyManager;
+    private final int port;
+    private final String host;
+    private final String protocol;
+
+    JSSEClient(CipherTestUtils cipherTest, String host, int port,
+            String protocols, String ciphersuite) throws Exception {
+        super(cipherTest, ciphersuite);
+        this.host = host;
+        this.port = port;
+        this.protocol = protocols;
+        this.keyManager = new MyX509KeyManager(
+                                    cipherTest.getClientKeyManager());
+        context = SSLContext.getInstance(TLS);
+    }
+
+    @Override
+    void runTest(CipherTestUtils.TestParameters params) throws Exception {
+        keyManager.setAuthType(params.clientAuth);
+        context.init(
+                new KeyManager[]{ keyManager },
+                new TrustManager[]{ cipherTest.getClientTrustManager() },
+                CipherTestUtils.secureRandom);
+        SSLSocketFactory factory = (SSLSocketFactory)context.getSocketFactory();
+
+        System.out.println("Connecting to server...");
+        try (SSLSocket socket = (SSLSocket) factory.createSocket(host, port)) {
+            socket.setSoTimeout(CipherTestUtils.TIMEOUT);
+            socket.setEnabledCipherSuites(params.cipherSuite.split(","));
+            if (params.protocol != null && !params.protocol.trim().isEmpty()
+                    && !params.protocol.trim().equals(DEFAULT)) {
+                socket.setEnabledProtocols(params.protocol.split(","));
+            }
+            CipherTestUtils.printInfo(socket);
+            InputStream in = socket.getInputStream();
+            OutputStream out = socket.getOutputStream();
+            sendRequest(in, out);
+            SSLSession session = socket.getSession();
+            session.invalidate();
+            String cipherSuite = session.getCipherSuite();
+            if (params.cipherSuite.equals(cipherSuite) == false) {
+                throw new RuntimeException("Negotiated ciphersuite mismatch: "
+                        + cipherSuite + " != " + params.cipherSuite);
+            }
+            String protocol = session.getProtocol();
+            if (!DEFAULT.equals(params.protocol)
+                    && !params.protocol.contains(protocol)) {
+                throw new RuntimeException("Negotiated protocol mismatch: "
+                        + protocol + " != " + params.protocol);
+            }
+            if (!cipherSuite.contains("DH_anon")) {
+                session.getPeerCertificates();
+            }
+            Certificate[] certificates = session.getLocalCertificates();
+            if (params.clientAuth == null) {
+                if (certificates != null) {
+                    throw new RuntimeException("Local certificates "
+                            + "should be null");
+                }
+            } else {
+                if ((certificates == null) || (certificates.length == 0)) {
+                    throw new RuntimeException("Certificates missing");
+                }
+                String keyAlg = certificates[0].getPublicKey().getAlgorithm();
+                if ("EC".equals(keyAlg)) {
+                    keyAlg = "ECDSA";
+                }
+                if (!params.clientAuth.equals(keyAlg)) {
+                    throw new RuntimeException("Certificate type mismatch: "
+                            + keyAlg + " != " + params.clientAuth);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/JSSEServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2010, 2016, 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.
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+public class JSSEServer extends CipherTestUtils.Server {
+
+    private final SSLServerSocket serverSocket;
+    private static volatile boolean closeServer = false;
+
+    JSSEServer(CipherTestUtils cipherTest, int serverPort,
+            String protocol, String cipherSuite) throws Exception {
+        super(cipherTest);
+        SSLContext serverContext = SSLContext.getInstance("TLS");
+        serverContext.init(new KeyManager[]{cipherTest.getServerKeyManager()},
+                new TrustManager[]{cipherTest.getServerTrustManager()},
+                CipherTestUtils.secureRandom);
+        SSLServerSocketFactory factory =
+                (SSLServerSocketFactory)serverContext.getServerSocketFactory();
+        serverSocket =
+                (SSLServerSocket) factory.createServerSocket(serverPort);
+        serverSocket.setEnabledProtocols(protocol.split(","));
+        serverSocket.setEnabledCipherSuites(cipherSuite.split(","));
+
+        CipherTestUtils.printInfo(serverSocket);
+    }
+
+    @Override
+    public void run() {
+        System.out.println("JSSE Server listening on port " + getPort());
+        while (!closeServer) {
+            try (final SSLSocket socket = (SSLSocket) serverSocket.accept()) {
+                socket.setSoTimeout(CipherTestUtils.TIMEOUT);
+
+                try (InputStream in = socket.getInputStream();
+                        OutputStream out = socket.getOutputStream()) {
+                    handleRequest(in, out);
+                    out.flush();
+                } catch (IOException e) {
+                    CipherTestUtils.addFailure(e);
+                    System.out.println("Got IOException:");
+                    e.printStackTrace(System.out);
+                }
+            } catch (Exception e) {
+                CipherTestUtils.addFailure(e);
+                System.out.println("Exception:");
+                e.printStackTrace(System.out);
+            }
+        }
+    }
+
+    int getPort() {
+        return serverSocket.getLocalPort();
+    }
+
+    @Override
+    public void close() throws IOException {
+        closeServer = true;
+        if (serverSocket != null && !serverSocket.isClosed()) {
+            serverSocket.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSClientPropertyTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2014, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8049432 8069038 8234723
+ * @summary New tests for TLS property jdk.tls.client.protocols
+ * @summary javax/net/ssl/TLS/TLSClientPropertyTest.java needs to be
+ *     updated for JDK-8061210
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm TLSClientPropertyTest NoProperty
+ * @run main/othervm TLSClientPropertyTest SSLv3
+ * @run main/othervm TLSClientPropertyTest TLSv1
+ * @run main/othervm TLSClientPropertyTest TLSv11
+ * @run main/othervm TLSClientPropertyTest TLSv12
+ * @run main/othervm TLSClientPropertyTest TLSv13
+ * @run main/othervm TLSClientPropertyTest TLS
+ * @run main/othervm TLSClientPropertyTest WrongProperty
+ */
+
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.List;
+import javax.net.ssl.SSLContext;
+
+/**
+ * Sets the property jdk.tls.client.protocols to one of this protocols:
+ * SSLv3,TLSv1,TLSv1.1,TLSv1.2 and TLSV(invalid) or removes this
+ * property (if any),then validates the default, supported and current
+ * protocols in the SSLContext.
+ */
+public class TLSClientPropertyTest {
+    private final String[] expectedSupportedProtos = new String[] {
+            "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"
+    };
+
+    public static void main(String[] args) throws Exception {
+
+        if (args.length < 1) {
+            throw new RuntimeException(
+                    "Incorrect arguments,expected arguments: testCase");
+        }
+
+        String[] expectedDefaultProtos;
+        String testCase = args[0];
+        String contextProtocol;
+        switch (testCase) {
+        case "NoProperty":
+            if (System.getProperty("jdk.tls.client.protocols") != null) {
+                System.getProperties().remove("jdk.tls.client.protocols");
+            }
+            contextProtocol = null;
+            expectedDefaultProtos = new String[] {
+                    "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"
+            };
+            break;
+        case "SSLv3":
+            contextProtocol = "SSLv3";
+            expectedDefaultProtos = new String[] {
+            };
+            break;
+        case "TLSv1":
+            contextProtocol = "TLSv1";
+            expectedDefaultProtos = new String[] {
+                    "TLSv1"
+            };
+            break;
+        case "TLSv11":
+            contextProtocol = "TLSv1.1";
+            expectedDefaultProtos = new String[] {
+                    "TLSv1", "TLSv1.1"
+            };
+            break;
+        case "TLSv12":
+            contextProtocol = "TLSv1.2";
+            expectedDefaultProtos = new String[] {
+                    "TLSv1", "TLSv1.1", "TLSv1.2"
+            };
+            break;
+        case "TLSv13":
+        case "TLS":
+            contextProtocol = "TLSv1.3";
+            expectedDefaultProtos = new String[] {
+                    "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"
+            };
+            break;
+        case "WrongProperty":
+            expectedDefaultProtos = new String[] {};
+            contextProtocol = "TLSV";
+            break;
+        default:
+            throw new RuntimeException("test case is wrong");
+        }
+        if (contextProtocol != null) {
+            System.setProperty("jdk.tls.client.protocols", contextProtocol);
+        }
+        try {
+            TLSClientPropertyTest test = new TLSClientPropertyTest();
+            test.test(contextProtocol, expectedDefaultProtos);
+            if (testCase.equals("WrongProperty")) {
+                throw new RuntimeException(
+                        "Test failed: NoSuchAlgorithmException " +
+                        "is expected when input wrong protocol");
+            } else {
+                System.out.println("Test " + contextProtocol + " passed");
+            }
+        } catch (NoSuchAlgorithmException nsae) {
+            if (testCase.equals("WrongProperty")) {
+                System.out.println("NoSuchAlgorithmException is expected,"
+                        + contextProtocol + " test passed");
+            } else {
+                throw nsae;
+            }
+        }
+
+    }
+
+    /**
+     * The parameter passed is the user enforced protocol. Does not catch
+     * NoSuchAlgorithmException, WrongProperty test will use it.
+     */
+    public void test(String expectedContextProto,
+            String[] expectedDefaultProtos) throws NoSuchAlgorithmException {
+
+        SSLContext context = null;
+        try {
+            if (expectedContextProto != null) {
+                context = SSLContext.getInstance(expectedContextProto);
+                context.init(null, null, null);
+            } else {
+                context = SSLContext.getDefault();
+            }
+            printContextDetails(context);
+        } catch (KeyManagementException ex) {
+            error(null, ex);
+        }
+
+        validateContext(expectedContextProto, expectedDefaultProtos, context);
+    }
+
+    /**
+     * Simple print utility for SSLContext's protocol details.
+     */
+    private void printContextDetails(SSLContext context) {
+        System.out.println("Default   Protocols: "
+                + Arrays.toString(context.getDefaultSSLParameters()
+                        .getProtocols()));
+        System.out.println("Supported Protocols: "
+                + Arrays.toString(context.getSupportedSSLParameters()
+                        .getProtocols()));
+        System.out.println("Current   Protocol : " + context.getProtocol());
+
+    }
+
+    /**
+     * Error handler.
+     */
+    private void error(String msg, Throwable tble) {
+        String finalMsg = "FAILED " + (msg != null ? msg : "");
+        if (tble != null) {
+            throw new RuntimeException(finalMsg, tble);
+        }
+        throw new RuntimeException(finalMsg);
+    }
+
+    /**
+     * Validates the SSLContext's protocols against the user enforced protocol.
+     */
+    private void validateContext(String expectedProto,
+            String[] expectedDefaultProtos, SSLContext context) {
+        if (expectedProto == null) {
+            expectedProto = "Default";
+        }
+        if (!context.getProtocol().equals(expectedProto)) {
+            error("Invalid current protocol: " + context.getProtocol()
+                    + ", Expected:" + expectedProto, null);
+        }
+        List<String> actualDefaultProtos = Arrays.asList(context
+                .getDefaultSSLParameters().getProtocols());
+        for (String p : expectedDefaultProtos) {
+            if (!actualDefaultProtos.contains(p)) {
+                error("Default protocol " + p + "missing", null);
+            }
+        }
+        List<String> actualSupportedProtos = Arrays.asList(context
+                .getSupportedSSLParameters().getProtocols());
+
+        for (String p : expectedSupportedProtos) {
+            if (!actualSupportedProtos.contains(p)) {
+                error("Expected to support protocol:" + p, null);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSDataExchangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS application data exchange using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSDataExchangeTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSDataExchangeTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=krb TLSDataExchangeTest
+ */
+
+/**
+ * Testing TLS application data exchange using each of the supported cipher
+ * suites.
+ */
+public class TLSDataExchangeTest {
+    public static void main(String[] args) {
+        DataExchangeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSEnginesClosureTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines closing using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=krb TLSEnginesClosureTest
+ */
+
+/**
+ * Testing TLS engines closing using each of the supported cipher suites.
+ */
+public class TLSEnginesClosureTest {
+    public static void main(String[] args) {
+        EnginesClosureTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSHandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines handshake using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSHandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSHandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=krb TLSHandshakeTest
+ */
+
+/**
+ * Testing TLS engines handshake using each of the supported cipher suites.
+ */
+public class TLSHandshakeTest {
+    public static void main(String[] args) {
+        HandshakeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSMFLNTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines handshake using each of the supported
+ *          cipher suites with different maximum fragment length. Testing of
+ *          MFLN extension.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSMFLNTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSMFLNTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=krb TLSMFLNTest
+ */
+
+/**
+ * Testing TLS engines handshake using each of the supported cipher suites with
+ * different maximum fragment length. Testing of MFLN extension.
+ */
+public class TLSMFLNTest {
+    public static void main(String[] args) {
+        MFLNTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSNotEnabledRC4Test.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines do not enable RC4 ciphers by default.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS TLSNotEnabledRC4Test
+ */
+
+/**
+ * Testing DTLS engines do not enable RC4 ciphers by default.
+ */
+public class TLSNotEnabledRC4Test {
+    public static void main(String[] args) throws Exception {
+        NotEnabledRC4Test.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSRehandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=krb TLSRehandshakeTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking using each of the supported cipher
+ * suites.
+ */
+public class TLSRehandshakeTest {
+    public static void main(String[] args) {
+        RehandshakeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSRehandshakeWithCipherChangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2017, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking with cipher change. New cipher
+ *          is taken randomly from the supporetd ciphers list.
+ * @key randomness
+ * @library /sun/security/krb5/auto /lib /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @build jdk.test.lib.RandomFactory
+ * @run main/othervm -Dtest.security.protocol=TLS TLSRehandshakeWithCipherChangeTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking with cipher change. New cipher is taken
+ * randomly from the supported ciphers list.
+ */
+public class TLSRehandshakeWithCipherChangeTest {
+    public static void main(String[] args) {
+        RehandshakeWithCipherChangeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSRehandshakeWithDataExTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking using each of the supported
+ *          cipher suites with application data exchange before and after
+ *          re-handshake and closing of the engines.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm TLSRehandshakeWithDataExTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=norm_sni TLSRehandshakeWithDataExTest
+ * @run main/othervm -Dtest.security.protocol=TLS -Dtest.mode=krb TLSRehandshakeWithDataExTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking using each of the supported cipher suites
+ * with application data exchange before and after re-handshake and closing of
+ * the engines.
+ */
+public class TLSRehandshakeWithDataExTest {
+    public static void main(String[] args) {
+        RehandshakeWithDataExTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TLSUnsupportedCiphersTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing that try to enable unsupported ciphers
+ *          causes IllegalArgumentException.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLS TLSUnsupportedCiphersTest
+ */
+
+/**
+ * Testing that a try to enable unsupported ciphers causes IllegalArgumentException.
+ */
+public class TLSUnsupportedCiphersTest {
+    public static void main(String[] args) {
+        UnsupportedCiphersTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TestJSSE.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2010, 2016, 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.
+ *
+ * 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.
+ */
+
+import java.security.Provider;
+import java.security.Security;
+
+public class TestJSSE {
+
+    private static final String LOCAL_IP = "127.0.0.1";
+
+    public static void main(String... args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        // enable debug output
+        System.setProperty("javax.net.debug", "ssl,record");
+
+        String srvProtocol = System.getProperty("SERVER_PROTOCOL");
+        String clnProtocol = System.getProperty("CLIENT_PROTOCOL");
+        String cipher = System.getProperty("CIPHER");
+        if (srvProtocol == null || clnProtocol == null || cipher == null) {
+            throw new IllegalArgumentException("Incorrect parameters");
+        }
+
+        System.out.println("ServerProtocol = " + srvProtocol);
+        System.out.println("ClientProtocol = " + clnProtocol);
+        System.out.println("Cipher         = " + cipher);
+
+        try (CipherTestUtils.Server srv = server(srvProtocol, cipher, args)) {
+            client(srv.getPort(), clnProtocol, cipher, args);
+        }
+    }
+
+    public static void client(int port, String protocols, String cipher,
+            String... exceptions) throws Exception {
+
+        String expectedExcp = exceptions.length >= 1 ? exceptions[0] : null;
+
+        System.out.println("This is client");
+        System.out.println("Testing protocol: " + protocols);
+        System.out.println("Testing cipher  : " + cipher);
+
+        CipherTestUtils.mainClient(
+            new JSSEFactory(LOCAL_IP, protocols, cipher, "Client JSSE"),
+            port, expectedExcp);
+    }
+
+    public static CipherTestUtils.Server server(String protocol,
+                String cipher, String... exceptions) throws Exception {
+
+        String expectedExcp = exceptions.length >= 1 ? exceptions[0] : null;
+
+        System.out.println("This is server");
+        System.out.println("Testing protocol: " + protocol);
+        System.out.println("Testing cipher  : " + cipher);
+
+        return CipherTestUtils.mainServer(
+            new JSSEFactory(null, protocol, cipher, "Server JSSE"),
+            expectedExcp);
+    }
+
+    private static class JSSEFactory extends CipherTestUtils.PeerFactory {
+
+        private final String cipher;
+        private final String protocol;
+        private final String host;
+        private final String name;
+
+        JSSEFactory(String host, String protocol, String cipher, String name) {
+            this.cipher = cipher;
+            this.protocol = protocol;
+            this.host = host;
+            this.name = name;
+        }
+
+        @Override
+        String getName() {
+            return name;
+        }
+
+        @Override
+        String getTestedCipher() {
+            return cipher;
+        }
+
+        @Override
+        String getTestedProtocol() {
+            return protocol;
+        }
+
+        @Override
+        CipherTestUtils.Client newClient(CipherTestUtils cipherTest, int port)
+                throws Exception {
+            return new JSSEClient(cipherTest, host, port, protocol, cipher);
+        }
+
+        @Override
+        CipherTestUtils.Server newServer(CipherTestUtils cipherTest, int port)
+                throws Exception {
+            return new JSSEServer(cipherTest, port, protocol, cipher);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TestJSSEClientDefaultProtocol.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8049429 8234723
+ * @modules java.management
+ *          jdk.crypto.ec/sun.security.ec
+ * @summary Test that all cipher suites work in all versions and all client
+ *          authentication types. The way this is setup the server is stateless
+ *          and all checking is done on the client side.
+ * @compile CipherTestUtils.java JSSEClient.java JSSEServer.java
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1
+ *              -DCLIENT_PROTOCOL=DEFAULT
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ *              -DCLIENT_PROTOCOL=DEFAULT
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ *              -DCLIENT_PROTOCOL=DEFAULT
+ *              -Djdk.tls.client.protocols=TLSv1
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1
+ *              -DCLIENT_PROTOCOL=DEFAULT
+ *              -Djdk.tls.client.protocols=TLSv1.2
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256
+ *          TestJSSE javax.net.ssl.SSLHandshakeException
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=DEFAULT
+ *              -Djdk.tls.client.protocols=TLSv1.3
+ *              -DCIPHER=TLS_AES_256_GCM_SHA384
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1
+ *              -DCLIENT_PROTOCOL=DEFAULT
+ *              -Djdk.tls.client.protocols=TLSv1.3
+ *              -DCIPHER=TLS_AES_256_GCM_SHA384
+ *          TestJSSE javax.net.ssl.SSLHandshakeException
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TestJSSEClientProtocol.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8049429 8172273 8234723
+ * @modules java.management
+ *          jdk.crypto.ec/sun.security.ec
+ * @summary Test that all cipher suites work in all versions and all client
+ *          authentication types. The way this is setup the server is stateless
+ *          and all checking is done on the client side.
+ * @compile CipherTestUtils.java JSSEClient.java JSSEServer.java
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCIPHER=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCIPHER=TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=SSLv2Hello,SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCIPHER=TLS_AES_256_GCM_SHA384
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv3
+ *              -DCLIENT_PROTOCOL=SSLv3
+ *              -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv3,TLSv1
+ *              -DCLIENT_PROTOCOL=TLSv1
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1
+ *              -DCLIENT_PROTOCOL=TLSv1.1
+ *              -DCIPHER=TLS_RSA_WITH_AES_256_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=TLSv1.2
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCLIENT_PROTOCOL=TLSv1.3
+ *              -DCIPHER=TLS_AES_256_GCM_SHA384
+ *          TestJSSE
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TestJSSENoCommonProtocols.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8049429
+ * @modules java.management
+ *          jdk.crypto.ec/sun.security.ec
+ * @summary Test that all cipher suites work in all versions and all client
+ *          authentication types. The way this is setup the server is stateless
+ *          and all checking is done on the client side.
+ * @compile CipherTestUtils.java JSSEClient.java JSSEServer.java
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=TLSv1
+ *              -DCLIENT_PROTOCOL=TLSv1.1,TLSv1.2
+ *              -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ *          TestJSSE javax.net.ssl.SSLHandshakeException
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLS/TestJSSEServerProtocol.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8049429 8234723
+ * @modules java.management
+ *          jdk.crypto.ec/sun.security.ec
+ * @summary Test that all cipher suites work in all versions and all client
+ *          authentication types. The way this is setup the server is stateless
+ *          and all checking is done on the client side.
+ * @compile CipherTestUtils.java JSSEClient.java JSSEServer.java
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=SSLv3
+ *              -DCLIENT_PROTOCOL=TLSv1.1,TLSv1.2
+ *              -DCIPHER=SSL_RSA_WITH_RC4_128_MD5
+ *          TestJSSE javax.net.ssl.SSLHandshakeException
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=TLSv1
+ *              -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=TLSv1.1
+ *              -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ *              -DCIPHER=TLS_RSA_WITH_AES_256_CBC_SHA
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=TLSv1.2
+ *              -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2
+ *              -DCIPHER=TLS_RSA_WITH_AES_128_GCM_SHA256
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=TLSv1.3
+ *              -DCLIENT_PROTOCOL=SSLv3,TLSv1,TLSv1.1,TLSv1.2,TLSv1.3
+ *              -DCIPHER=TLS_AES_256_GCM_SHA384
+ *          TestJSSE
+ * @run main/othervm
+ *              -DSERVER_PROTOCOL=TLSv1.2
+ *              -DCLIENT_PROTOCOL=TLSv1.3
+ *              -DCIPHER=TLS_AES_256_GCM_SHA384
+ *          TestJSSE javax.net.ssl.SSLHandshakeException
+ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/BufferOverflowUnderflowTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngine incorrect app data packages unwrapping.
+ */
+public class BufferOverflowUnderflowTest extends SSLEngineTestCase {
+
+    private final String MESSAGE = "Hello peer!";
+
+    public static void main(String[] args) {
+        BufferOverflowUnderflowTest test = new BufferOverflowUnderflowTest();
+        setUpAndStartKDCIfNeeded();
+        test.runTests();
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+        checkBufferOverflowOnWrap(clientEngine);
+        checkBufferOverflowOnWrap(serverEngine);
+        checkBufferOverflowOnUnWrap(clientEngine, serverEngine);
+        checkBufferOverflowOnUnWrap(serverEngine, clientEngine);
+        checkBufferUnderflowOnUnWrap(serverEngine, clientEngine);
+        checkBufferUnderflowOnUnWrap(clientEngine, serverEngine);
+    }
+
+    private void checkBufferOverflowOnWrap(SSLEngine engine)
+            throws SSLException {
+        String mode = engine.getUseClientMode() ? "client"
+                : "server";
+        System.out.println("================================================="
+                + "===========");
+        System.out.println("Testing SSLEngine buffer overflow"
+                + " on wrap by " + mode);
+        ByteBuffer app = ByteBuffer.wrap(MESSAGE.getBytes());
+        //Making net buffer size less than required by 1 byte.
+        ByteBuffer net = ByteBuffer
+                .allocate(engine.getSession().getPacketBufferSize() - 1);
+        SSLEngineResult r = engine.wrap(app, net);
+        checkResult(r, SSLEngineResult.Status.BUFFER_OVERFLOW);
+        System.out.println("Passed");
+    }
+
+    private void checkBufferOverflowOnUnWrap(SSLEngine wrappingEngine,
+            SSLEngine unwrappingEngine)
+            throws SSLException {
+        String wrapperMode = wrappingEngine.getUseClientMode() ? "client"
+                : "server";
+        String unwrapperMode = unwrappingEngine.getUseClientMode() ? "client"
+                : "server";
+        if (wrapperMode.equals(unwrapperMode)) {
+            throw new Error("Test error: both engines are in the same mode!");
+        }
+        System.out.println("================================================="
+                + "===========");
+        System.out.println("Testing SSLEngine buffer overflow"
+                + " on unwrap by " + unwrapperMode);
+        ByteBuffer app = ByteBuffer.wrap(MESSAGE.getBytes());
+        ByteBuffer net = ByteBuffer
+                .allocate(wrappingEngine.getSession().getPacketBufferSize());
+        SSLEngineResult r = wrappingEngine.wrap(app, net);
+        checkResult(r, SSLEngineResult.Status.OK);
+        //Making app buffer size less than required by 1 byte.
+        app = ByteBuffer.allocate(MESSAGE.length() - 1);
+        net.flip();
+        r = unwrappingEngine.unwrap(net, app);
+        checkResult(r, SSLEngineResult.Status.BUFFER_OVERFLOW);
+        System.out.println("Passed");
+    }
+
+    private void checkBufferUnderflowOnUnWrap(SSLEngine wrappingEngine,
+            SSLEngine unwrappingEngine)
+            throws SSLException {
+        String wrapperMode = wrappingEngine.getUseClientMode() ? "client"
+                : "server";
+        String unwrapperMode = unwrappingEngine.getUseClientMode() ? "client"
+                : "server";
+        if (wrapperMode.equals(unwrapperMode)) {
+            throw new Error("Test error: both engines are in the same mode!");
+        }
+        System.out.println("================================================="
+                + "===========");
+        System.out.println("Testing SSLEngine buffer underflow"
+                + " on unwrap by " + unwrapperMode);
+        ByteBuffer app = ByteBuffer.wrap(MESSAGE.getBytes());
+        ByteBuffer net = ByteBuffer
+                .allocate(wrappingEngine.getSession().getPacketBufferSize());
+        SSLEngineResult r = wrappingEngine.wrap(app, net);
+        checkResult(r, SSLEngineResult.Status.OK);
+        app = ByteBuffer.allocate(unwrappingEngine.getSession()
+                .getApplicationBufferSize());
+        net.flip();
+        //Making net buffer size less than size of dtls message.
+        net.limit(net.limit() - 1);
+        r = unwrappingEngine.unwrap(net, app);
+        checkResult(r, SSLEngineResult.Status.BUFFER_UNDERFLOW);
+        System.out.println("Passed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/CipherSuite.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * SSL/TLS cipher suites.
+ */
+public enum CipherSuite {
+
+    TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256(
+            0xCCAA, KeyExAlgorithm.DHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256(
+            0xCCA9, KeyExAlgorithm.ECDHE_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256(
+            0xCCA8, KeyExAlgorithm.ECDHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(
+            0xC032, KeyExAlgorithm.ECDH_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(
+            0xC031, KeyExAlgorithm.ECDH_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(
+            0xC030, KeyExAlgorithm.ECDHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(
+            0xC02F, KeyExAlgorithm.ECDHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(
+            0xC02E, KeyExAlgorithm.ECDH_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(
+            0xC02D, KeyExAlgorithm.ECDH_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(
+            0xC02C, KeyExAlgorithm.ECDHE_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(
+            0xC02B, KeyExAlgorithm.ECDHE_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(
+            0xC02A, KeyExAlgorithm.ECDH_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(
+            0xC029, KeyExAlgorithm.ECDH_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(
+            0xC028, KeyExAlgorithm.ECDHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(
+            0xC027, KeyExAlgorithm.ECDHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(
+            0xC026, KeyExAlgorithm.ECDH_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(
+            0xC025, KeyExAlgorithm.ECDH_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(
+            0xC025, KeyExAlgorithm.ECDH_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(
+            0xC024, KeyExAlgorithm.ECDHE_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(
+            0xC023, KeyExAlgorithm.ECDHE_ECDSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_anon_WITH_AES_256_CBC_SHA(
+            0xC019, KeyExAlgorithm.ECDH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_anon_WITH_AES_128_CBC_SHA(
+            0xC018, KeyExAlgorithm.ECDH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA(
+            0xC017, KeyExAlgorithm.ECDH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_anon_WITH_RC4_128_SHA(
+            0xC016, KeyExAlgorithm.ECDH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_anon_WITH_NULL_SHA(
+            0xC015, KeyExAlgorithm.ECDH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(
+            0xC014, KeyExAlgorithm.ECDHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(
+            0xC013, KeyExAlgorithm.ECDHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA(
+            0xC012, KeyExAlgorithm.ECDHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_RC4_128_SHA(
+            0xC011, KeyExAlgorithm.ECDHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_RSA_WITH_NULL_SHA(
+            0xC010, KeyExAlgorithm.ECDHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(
+            0xC00F, KeyExAlgorithm.ECDH_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(
+            0xC00E, KeyExAlgorithm.ECDH_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA(
+            0xC00D, KeyExAlgorithm.ECDH_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_RC4_128_SHA(
+            0xC00C, KeyExAlgorithm.ECDH_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_RSA_WITH_NULL_SHA(
+            0xC00B, KeyExAlgorithm.ECDH_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(
+            0xC00A, KeyExAlgorithm.ECDHE_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(
+            0xC009, KeyExAlgorithm.ECDHE_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA(
+            0xC008, KeyExAlgorithm.ECDHE_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA(
+            0xC007, KeyExAlgorithm.ECDHE_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDHE_ECDSA_WITH_NULL_SHA(
+            0xC006, KeyExAlgorithm.ECDHE_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA(
+            0xC003, KeyExAlgorithm.ECDH_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_RC4_128_SHA(
+            0xC002, KeyExAlgorithm.ECDH_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_NULL_SHA(
+            0xC001, KeyExAlgorithm.ECDH_ECDSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_EMPTY_RENEGOTIATION_INFO_SCSV(
+            0x00FF, KeyExAlgorithm.SCSV, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_AES_256_GCM_SHA384(
+            0x1302, null, Protocol.TLSV1_3, Protocol.TLSV1_3),
+    TLS_AES_128_GCM_SHA256(
+            0x1301, null, Protocol.TLSV1_3, Protocol.TLSV1_3),
+    TLS_DH_anon_WITH_AES_256_GCM_SHA384(
+            0x00A7, KeyExAlgorithm.DH_ANON, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DH_anon_WITH_AES_128_GCM_SHA256(
+            0x00A6, KeyExAlgorithm.DH_ANON, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(
+            0x00A3, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(
+            0x00A2, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(
+            0x009F, KeyExAlgorithm.DHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(
+            0x009E, KeyExAlgorithm.DHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_AES_256_GCM_SHA384(
+            0x009D, KeyExAlgorithm.RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_AES_128_GCM_SHA256(
+            0x009C, KeyExAlgorithm.RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DH_anon_WITH_AES_256_CBC_SHA256(
+            0x006D, KeyExAlgorithm.DH_ANON, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DH_anon_WITH_AES_128_CBC_SHA256(
+            0x006C, KeyExAlgorithm.DH_ANON, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(
+            0x006B, KeyExAlgorithm.DHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(
+            0x006A, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(
+            0x0067, KeyExAlgorithm.DHE_RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(
+            0x004C, KeyExAlgorithm.ECDH_ECDSA, Protocol.TLSV1, Protocol.TLSV1_2),
+    TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(
+            0x0040, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_AES_256_CBC_SHA256(
+            0x003D, KeyExAlgorithm.RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_AES_128_CBC_SHA256(
+            0x003C, KeyExAlgorithm.RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_NULL_SHA256(
+            0x003B, KeyExAlgorithm.RSA, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_DH_anon_WITH_AES_256_CBC_SHA(
+            0x003A, KeyExAlgorithm.DH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA(
+            0x0039, KeyExAlgorithm.DHE_RSA, Protocol.TLSV1, Protocol.TLSV1_2),
+    TLS_DHE_DSS_WITH_AES_256_CBC_SHA(
+            0x0038, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_AES_256_CBC_SHA(
+            0x0035, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_DH_anon_WITH_AES_128_CBC_SHA(
+            0x0034, KeyExAlgorithm.DH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA(
+            0x0033, KeyExAlgorithm.DHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_DHE_DSS_WITH_AES_128_CBC_SHA(
+            0x0032, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+    TLS_RSA_WITH_AES_128_CBC_SHA(
+            0x002F, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_KRB5_WITH_3DES_EDE_CBC_MD5(
+            0x0023, KeyExAlgorithm.KRB5, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_KRB5_WITH_DES_CBC_MD5(
+            0x0022,KeyExAlgorithm.KRB5,  Protocol.SSLV3, Protocol.TLSV1_1),
+    TLS_KRB5_WITH_3DES_EDE_CBC_SHA(
+            0x001F, KeyExAlgorithm.KRB5, Protocol.SSLV3, Protocol.TLSV1_2),
+    TLS_KRB5_WITH_DES_CBC_SHA(
+            0x001E, KeyExAlgorithm.KRB5, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_DH_anon_WITH_3DES_EDE_CBC_SHA(
+            0x001B, KeyExAlgorithm.DH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_DH_anon_WITH_DES_CBC_SHA(
+            0x001A, KeyExAlgorithm.DH_ANON, Protocol.SSLV3, Protocol.TLSV1_1),
+    SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA(
+            0x0019, KeyExAlgorithm.DH_ANON_EXPORT, Protocol.SSLV3, Protocol.TLSV1),
+    SSL_DH_anon_WITH_RC4_128_MD5(
+            0x0018, KeyExAlgorithm.DH_ANON, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_DH_anon_EXPORT_WITH_RC4_40_MD5(
+            0x0017, KeyExAlgorithm.DH_ANON_EXPORT, Protocol.SSLV3, Protocol.TLSV1),
+    SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA(
+            0x0016, KeyExAlgorithm.DHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_DHE_RSA_WITH_DES_CBC_SHA(
+            0x0015, KeyExAlgorithm.DHE_RSA, Protocol.SSLV3, Protocol.TLSV1_1),
+    SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA(
+            0x0014, KeyExAlgorithm.DHE_RSA_EXPORT, Protocol.SSLV3, Protocol.TLSV1),
+    SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA(
+            0x0013, KeyExAlgorithm.DHE_DSS, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_DHE_DSS_WITH_DES_CBC_SHA(
+            0x0012, KeyExAlgorithm.DHE_DSS, Protocol.SSLV3, Protocol.TLSV1_1),
+    SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA(
+            0x0011, KeyExAlgorithm.DHE_DSS_EXPORT, Protocol.SSLV3, Protocol.TLSV1),
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA(
+            0x000A, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_RSA_WITH_DES_CBC_SHA(
+            0x0009, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_1),
+    SSL_RSA_EXPORT_WITH_DES40_CBC_SHA(
+            0x0008, KeyExAlgorithm.RSA_EXPORT, Protocol.SSLV3, Protocol.TLSV1),
+    SSL_RSA_WITH_RC4_128_SHA(
+            0x0005, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_RSA_WITH_RC4_128_MD5(
+            0x0004, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_RSA_EXPORT_WITH_RC4_40_MD5(
+            0x0003, KeyExAlgorithm.RSA_EXPORT, Protocol.SSLV3, Protocol.TLSV1),
+    SSL_RSA_WITH_NULL_SHA(
+            0x0002, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
+    SSL_RSA_WITH_NULL_MD5(
+            0x0001, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2);
+
+    public final int id;
+    public final KeyExAlgorithm keyExAlgorithm;
+    public final Protocol startProtocol;
+    public final Protocol endProtocol;
+
+    private CipherSuite(
+            int id,
+            KeyExAlgorithm keyExAlgorithm,
+            Protocol startProtocol,
+            Protocol endProtocol) {
+        this.id = id;
+        this.keyExAlgorithm = keyExAlgorithm;
+        this.startProtocol = startProtocol;
+        this.endProtocol = endProtocol;
+    }
+
+    public boolean supportedByProtocol(Protocol protocol) {
+        return startProtocol.id <= protocol.id
+                && protocol.id <= endProtocol.id;
+    }
+
+    public static CipherSuite cipherSuite(String name) {
+        return CipherSuite.valueOf(CipherSuite.class, name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/ConcurrentClientAccessTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+/*
+ * @test
+ * @bug 8208496
+ * @summary Test to verify concurrent behavior of TLS.
+ * @run main/othervm ConcurrentClientAccessTest
+ */
+public class ConcurrentClientAccessTest {
+
+    private static final int THREADS = 50;
+
+    public static void main(String[] args) throws Exception {
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        for (String tlsProtocol : new String[]{"TLSv1.3", "TLSv1.2",
+            "TLSv1.1", "TLSv1"}) {
+            System.out.printf("Protocol: %s%n", tlsProtocol);
+            CountDownLatch tillServerReady = new CountDownLatch(1);
+            Server server = new Server(tlsProtocol, tillServerReady);
+            server.start();
+
+            // Wait till server is ready to accept connection.
+            tillServerReady.await();
+            CountDownLatch tillClientComplete = new CountDownLatch(THREADS);
+            ExecutorService executor = null;
+            try {
+                executor = newExecutorService();
+                // Run 50 TLS clients for concurrent access to TLS Port.
+                for (int count = 1; count <= THREADS; count++) {
+                    Client client = new Client(tlsProtocol, server.port,
+                            tillClientComplete);
+                    executor.execute(client);
+                    // If Client has any Exception indicates problem
+                    if (client.exception != null) {
+                        throw new RuntimeException(client.exception);
+                    }
+                }
+                // Wait till all client thread complete execution
+                tillClientComplete.await();
+                System.out.println("All client processed successfully.");
+            } finally {
+                if (executor != null) {
+                    executor.shutdown();
+                }
+                // Fail Safe: Shutdown the server
+                server.stopServer();
+            }
+            // If Sever has any Exception indicates problem
+            if (server.exception != null) {
+                throw new RuntimeException(server.exception);
+            }
+            System.out.println();
+        }
+    }
+
+    public static class Server implements Runnable {
+
+        private volatile int port = 0;
+        private final String tlsProtocol;
+        private final CountDownLatch tillServerReady;
+        private volatile Exception exception;
+        private SSLServerSocket sslServerSocket;
+
+        public Server(String tlsProtocol, CountDownLatch tillServerReady) {
+            this.tlsProtocol = tlsProtocol;
+            this.tillServerReady = tillServerReady;
+        }
+
+        public void start() {
+
+            ExecutorService executor = null;
+            try {
+                executor = newExecutorService();
+                executor.execute(this);
+            } finally {
+                if (executor != null) {
+                    executor.shutdown();
+                }
+            }
+        }
+
+        /*
+         * Define the server side operation.
+         */
+        void doServerSide() throws Exception {
+
+            SSLContext ctx = getSSLContext(tlsProtocol);
+            SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
+            sslServerSocket = (SSLServerSocket) sslssf.createServerSocket(port);
+            port = sslServerSocket.getLocalPort();
+            System.out.println("Server listening on port: " + port);
+            sslServerSocket.setEnabledProtocols(new String[]{tlsProtocol});
+            // ServerSocket will timeout after waiting for 20 seconds
+            // before accepting a connection
+            sslServerSocket.setSoTimeout(20000);
+            // Signal Client, the server is ready to accept client request.
+            tillServerReady.countDown();
+            while (sslServerSocket != null && !sslServerSocket.isClosed()) {
+                try (SSLSocket sslSocket
+                        = (SSLSocket) sslServerSocket.accept()) {
+                    try (InputStream sslIS = sslSocket.getInputStream();
+                            OutputStream sslOS
+                            = sslSocket.getOutputStream();) {
+                        sslIS.read();
+                        sslOS.write(85);
+                        sslOS.flush();
+                    }
+                } catch (SocketTimeoutException | SocketException e) {
+                    // Let the server exit
+                    return;
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                this.exception = e;
+            } finally {
+                // Stop server
+                stopServer();
+            }
+        }
+
+        public void stopServer() {
+            if (sslServerSocket != null && !sslServerSocket.isClosed()) {
+                System.out.println("Stopping Server.");
+                try {
+                    sslServerSocket.close();
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    public static class Client implements Runnable {
+
+        private final int serverPort;
+        private final String tlsProtocol;
+        private final CountDownLatch tillClientComplete;
+        private volatile Exception exception;
+
+        public Client(String tlsProtocol, int serverPort,
+                CountDownLatch tillClientComplete) {
+            this.tlsProtocol = tlsProtocol;
+            this.serverPort = serverPort;
+            this.tillClientComplete = tillClientComplete;
+        }
+
+        void doClientSide() throws Exception {
+
+            SSLContext ctx = getSSLContext(this.tlsProtocol);
+            SSLSocketFactory sslsf = ctx.getSocketFactory();
+            try (SSLSocket sslSocket
+                    = (SSLSocket) sslsf.createSocket("localhost", serverPort)) {
+                sslSocket.setEnabledProtocols(new String[]{this.tlsProtocol});
+                try (InputStream sslIS = sslSocket.getInputStream();
+                        OutputStream sslOS = sslSocket.getOutputStream()) {
+                    sslOS.write(86);
+                    sslOS.flush();
+                    sslIS.read();
+                }
+            } finally {
+                tillClientComplete.countDown();
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                // Print the exception for debug purpose.
+                e.printStackTrace(System.out);
+                this.exception = e;
+            }
+        }
+    }
+
+    // Get the ssl context
+    protected static SSLContext getSSLContext(String tlsProtocol)
+            throws Exception {
+
+        // Generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // Create a key store
+        KeyStore ts = KeyStore.getInstance("PKCS12");
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+        ts.load(null, null);
+        ks.load(null, null);
+        char passphrase[] = "passphrase".toCharArray();
+
+        // Import the trusted cert
+        ts.setCertificateEntry("trusted-cert-"
+                + KeyType.rsa_pkcs1_sha256.getKeyType(),
+                cf.generateCertificate(new ByteArrayInputStream(
+                        KeyType.rsa_pkcs1_sha256.getTrustedCert().getBytes())));
+
+        boolean hasKeyMaterials = KeyType.rsa_pkcs1_sha256.getEndCert() != null
+                && KeyType.rsa_pkcs1_sha256.getPrivateKey() != null;
+        if (hasKeyMaterials) {
+
+            // Generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(
+                            KeyType.rsa_pkcs1_sha256.getPrivateKey()));
+            KeyFactory kf = KeyFactory.getInstance(
+                    KeyType.rsa_pkcs1_sha256.getKeyType());
+            PrivateKey priKey = kf.generatePrivate(priKeySpec);
+
+            // Generate certificate chain
+            Certificate keyCert = cf.generateCertificate(
+                    new ByteArrayInputStream(
+                            KeyType.rsa_pkcs1_sha256.getEndCert().getBytes()));
+            Certificate[] chain = new Certificate[]{keyCert};
+
+            // Import the key entry.
+            ks.setKeyEntry("cert-" + KeyType.rsa_pkcs1_sha256.getKeyType(),
+                    priKey, passphrase, chain);
+        }
+
+        // Create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ts);
+
+        SSLContext context = SSLContext.getInstance(tlsProtocol);
+        if (hasKeyMaterials) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            context.init(null, tmf.getTrustManagers(), null);
+        }
+        return context;
+    }
+
+    private static ExecutorService newExecutorService() {
+        return Executors.newCachedThreadPool((Runnable r) -> {
+            Thread t = Executors.defaultThreadFactory()
+                    .newThread(r);
+            t.setDaemon(true);
+            return t;
+        });
+    }
+}
+
+enum KeyType {
+
+    rsa_pkcs1_sha256(
+            "RSA",
+            /**
+             * Signature Algorithm: sha256WithRSAEncryption
+             * Issuer: CN = localhost
+             * Validity Not Before: Jun 4 15:22:04 2018 GMT
+             * Not After: May 30 15:22:04 2038 GMT
+             * Subject: CN = localhost
+             * Public Key Algorithm: rsaEncryption
+             */
+            "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDBjCCAe6gAwIBAgIUc8yTYekR2LuXkkCJYqWlS/pBMKIwDQYJKoZIhvcNAQEL\n"
+            + "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNDE1MjIwNFoXDTM4MDUz\n"
+            + "MDE1MjIwNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
+            + "AAOCAQ8AMIIBCgKCAQEA2jDPGMogc9dq2w5b+FHqbfaGPokRmyObiU8y/l/dqkM5\n"
+            + "9IV+qj8VQUI4NtpdCTWr16812z4AjXrk5HIBrECfQbHPUcm1rme5YVZ0WxV0+Ufy\n"
+            + "hDmrGwDLhkxGqc3hOhRrlF2wdXeUfjIzhvS9+S/401++t/jvq+cqFF1BHnzYOu+l\n"
+            + "nbi/o95Oqo8MlwiRqg3xy3fNRfqXk7DWy+QT8s+Vc3Pcj1EW6K0iJJ23BVTdv6YT\n"
+            + "Ja5IKiWL4XsLht3fWvZwF+PoYfKb+JYflt0rafpxg9xkowe7GnGh2SpV7bJaH/QN\n"
+            + "3PTFEKQWgWHjWwjR171GOzSaEgaklvKde6+zNWeYKwIDAQABo1AwTjAdBgNVHQ4E\n"
+            + "FgQUqCtGe8/Ky4O6pH7xeTUy9yrv4n0wHwYDVR0jBBgwFoAUqCtGe8/Ky4O6pH7x\n"
+            + "eTUy9yrv4n0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAuqch30im\n"
+            + "M09sARarbfK3OExqYK2xoyuUscgTqQNDpNL2gMdXY9e0lTmGVgw9pVYtNZPZRxem\n"
+            + "jR5an2XegvG9qVU6vLENDwLCqZgsTb2gvmXngiG8NVcYd81GNqD228mkgBosNJku\n"
+            + "6BR+C8zlURzsNEt657eVvIp9ObGomdAbWhpdqihBD180PP18DIBWopyfHfJtT5FA\n"
+            + "U2kSPBp+P1EtdceW0zfwv3rF8hwRbnQBzuoYrZfn2PiMYaGUqOgbqUltCMD/Dp9G\n"
+            + "xK0nfAXEwIqHWWnijGwAd6YrszMjBUcSGmlehdF+XZK6jHNlw64RB4WTfavr+rY0\n"
+            + "dTe6g4o5GYr9nQ==\n"
+            + "-----END CERTIFICATE-----\n",
+            //
+            // Private key.
+            //
+            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDaMM8YyiBz12rb\n"
+            + "Dlv4Uept9oY+iRGbI5uJTzL+X92qQzn0hX6qPxVBQjg22l0JNavXrzXbPgCNeuTk\n"
+            + "cgGsQJ9Bsc9RybWuZ7lhVnRbFXT5R/KEOasbAMuGTEapzeE6FGuUXbB1d5R+MjOG\n"
+            + "9L35L/jTX763+O+r5yoUXUEefNg676WduL+j3k6qjwyXCJGqDfHLd81F+peTsNbL\n"
+            + "5BPyz5Vzc9yPURborSIknbcFVN2/phMlrkgqJYvhewuG3d9a9nAX4+hh8pv4lh+W\n"
+            + "3Stp+nGD3GSjB7sacaHZKlXtslof9A3c9MUQpBaBYeNbCNHXvUY7NJoSBqSW8p17\n"
+            + "r7M1Z5grAgMBAAECggEAHs/7vw10TcejEHJTrJqs14CT7qresKDzqw1jLycMn6nE\n"
+            + "unJLs/EaqE+Yrq5hqxZIQTo+CcsUuuYbAuPStqedleJtW6h3nryJImTaI67BCR8O\n"
+            + "8XtPXY3cMAf/hqVLZC9UDey5Ka2Ma9HdEvbnCRSsN/VycnqWJhmMCLouowaQZqoE\n"
+            + "VopscUix8GqELv0vEo2CszZfUjtSVbNTlNgwDf5U7eSKXMuFsnSn/LE7AMvHsEyo\n"
+            + "HatxogwlM/WjpTnf/WIeJY3VhaK10IsP6OEgUn/p4VtI2DQ/TJdgYrvD5vhjY8ip\n"
+            + "XuUPuPILRvJWo8dRXJqa4diXB12q5YhP8iiOp4BgkQKBgQD1GtlOR+JVgOzpQ11h\n"
+            + "s5/iJOsczee80pQscbSRJnzSsIaP9WM8CyJgvbPxIQxLUQeYnxM/bxNKkpJtzxRK\n"
+            + "pob+v4NoRn8PTpqbOp1obmWJT7uHTaoeavQo7r7uZI4i3eEgHCCQkMzpqzz7UFTY\n"
+            + "2Yst7bBTPUivlSVQQBEc8bLpeQKBgQDj47EjpAlh8DmJRTElg58t+XJehXGTqmlx\n"
+            + "nYu8DQLSzGbOQ/Z4srakC1mkM0LHCmULIIWk3KhV1GBCeArv7DlZ9A1SkI95bsq9\n"
+            + "GBeQpovL0PXKkOOWMJBklP/CTECO4eyA8r6c1d8wytBb6MrJ8bi74DdT+JlFjK5A\n"
+            + "zNoeNx6JwwKBgQCehIPABeuSYvRVlDTDqFkh98B6+4wBaatc5xjhuyOFW5dbaVeJ\n"
+            + "kKXmLSpAK6B44WnpQhA/uUWfuBWtoPy9nt+1yARjnxwzuSFyfUEqNiPC32coBYmd\n"
+            + "bIyGIIopQa1PTXJ4wtgoxw1PnmitHHITYPaLeKrN2te0fuAH+7dVodeU+QKBgAct\n"
+            + "VJbaw7Dh7+3yz+lui8TW5lMzwK/13fxGCfCSOFSLO3Gjkk+a0UW5VclmE+RQ333K\n"
+            + "OGtIx8RsO9vcC/wiZGwA06qWAu7AHoJ2D8fudtikbBlFFuXUAbgpOSTVYfMeCmTF\n"
+            + "QFuQIMdYm9dJLZnOkxLXrOZoHeui0poX2Ya6FawhAoGAAI/QCyDbuvnJzGmjSbvl\n"
+            + "5Ndr9lNAansCXaUzXuVLp6dD6PnB8HVCE8tdETZrcXseyTBeltaxAhj+tCybJvDO\n"
+            + "sV8UmPR0w9ibExmUIVGX5BpoRlB/KWxEG3ar/wJbUZVZ2oSdIAZvCvdbN956SLDg\n"
+            + "Pg5M5wrRqs71s2EiIJd0HrU="
+    );
+    private final String keyType;
+    private final String trustedCert;
+    private final String endCert;
+    private final String privateKey;
+
+    private KeyType(String keyType, String selfCert, String privateKey) {
+        this.keyType = keyType;
+        this.trustedCert = selfCert;
+        this.endCert = selfCert;
+        this.privateKey = privateKey;
+    }
+
+    public String getKeyType() {
+        return keyType;
+    }
+
+    public String getTrustedCert() {
+        return trustedCert;
+    }
+
+    public String getEndCert() {
+        return endCert;
+    }
+
+    public String getPrivateKey() {
+        return privateKey;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/DataExchangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngine application data exchange using each of the supported cipher
+ * suites.
+ */
+public class DataExchangeTest extends SSLEngineTestCase {
+
+    public static void main(String[] args) {
+        DataExchangeTest test = new DataExchangeTest();
+        setUpAndStartKDCIfNeeded();
+        test.runTests();
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+        sendApplicationData(clientEngine, serverEngine);
+        sendApplicationData(serverEngine, clientEngine);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/EnginesClosureTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngines closing using each of the supported cipher suites.
+ */
+public class EnginesClosureTest extends SSLEngineTestCase {
+
+    public static void main(String[] args) {
+        EnginesClosureTest test = new EnginesClosureTest();
+        setUpAndStartKDCIfNeeded();
+        test.runTests();
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        closingTest(cipher, true);
+        closingTest(cipher, false);
+    }
+
+    private void closingTest(String cipher, boolean clientCloses)
+            throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+        if (clientCloses) {
+            closeEngines(clientEngine, serverEngine);
+        } else {
+            closeEngines(serverEngine, clientEngine);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/HandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngines handshake using each of the supported cipher suites.
+ */
+public class HandshakeTest extends SSLEngineTestCase {
+
+    public static void main(String[] args) {
+        HandshakeTest test = new HandshakeTest();
+        setUpAndStartKDCIfNeeded();
+        test.runTests();
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/KeyAlgorithm.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * Key algorithms.
+ */
+public enum KeyAlgorithm {
+
+    DSA("DSA"),
+    RSA("RSA"),
+    EC("EC"),
+    RSASSAPSS("RSASSA-PSS");
+
+    public final String name;
+
+    private KeyAlgorithm(String name) {
+        this.name = name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/KeyExAlgorithm.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * Key exchange algorithms.
+ */
+public enum KeyExAlgorithm {
+
+    DH_ANON,
+    DH_ANON_EXPORT,
+    DHE_DSS,
+    DHE_DSS_EXPORT,
+    DHE_RSA,
+    DHE_RSA_EXPORT,
+    ECDH_ANON,
+    ECDH_ECDSA,
+    ECDH_RSA,
+    ECDHE_ECDSA,
+    ECDHE_RSA,
+    KRB5,
+    RSA,
+    RSA_EXPORT,
+    SCSV
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/MFLNTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngines handshake using each of the supported cipher suites with
+ * different maximum fragment length. Testing of MFLN extension.
+ */
+public class MFLNTest extends SSLEngineTestCase {
+
+    public static void main(String[] args) {
+        setUpAndStartKDCIfNeeded();
+        System.setProperty("jsse.enableMFLNExtension", "true");
+        for (int mfl = 4096; mfl >= 256; mfl /= 2) {
+            System.out.println("=============================================="
+                    + "==============");
+            System.out.printf("Testsing DTLS handshake with MFL = %d%n", mfl);
+            MFLNTest test = new MFLNTest(mfl);
+            test.runTests();
+        }
+    }
+
+    protected MFLNTest(int maxPacketSize) {
+        super(maxPacketSize);
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/NotEnabledRC4Test.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Testing SSLEngines do not enable RC4 ciphers by default.
+ */
+public class NotEnabledRC4Test {
+
+    public static void main(String[] s) throws Exception {
+        SSLContext context = SSLEngineTestCase.getContext();
+        SSLEngine clientEngine = context.createSSLEngine();
+        clientEngine.setUseClientMode(true);
+        SSLEngine serverEngine = context.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        String[] cliEnabledCiphers = clientEngine.getEnabledCipherSuites();
+        rc4Test(cliEnabledCiphers, true);
+        String[] srvEnabledCiphers = serverEngine.getEnabledCipherSuites();
+        rc4Test(srvEnabledCiphers, false);
+    }
+
+    private static void rc4Test(String[] ciphers, boolean isClient) {
+        String mode = isClient ? "client" : "server";
+        for (String cipher : ciphers) {
+            if (cipher.contains("RC4")) {
+                throw new AssertionError("RC4 cipher " + cipher + " is enabled"
+                        + " by default on " + mode + " SSLEngine,"
+                        + " but it should not!");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/Protocol.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+public enum Protocol {
+
+    SSLV2HELLO(0x0002, "SSLv2Hello"),
+    SSLV3     (0x0300, "SSLv3"),
+    TLSV1     (0x0301, "TLSv1"),
+    TLSV1_1   (0x0302, "TLSv1.1"),
+    TLSV1_2   (0x0303, "TLSv1.2"),
+    TLSV1_3   (0x0304, "TLSv1.3"),
+
+    DTLS1_3   (0xFEFC, "DTLSv1.3"),
+    DTLS1_2   (0xFEFD, "DTLSv1.2"),
+    DTLS1_0   (0xFEFF, "DTLSv1.0");
+
+    public final int id;
+    public final String name;
+
+    private Protocol(int id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public String toString() {
+        return name;
+    }
+
+    public static Protocol protocol(String name) {
+        for (Protocol protocol : values()) {
+            if (protocol.name.equals(name)) {
+                return protocol;
+            }
+        }
+
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/RehandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngines re-handshaking using each of the supported cipher
+ * suites.
+ */
+public class RehandshakeTest extends SSLEngineTestCase {
+
+    public static void main(String[] args) {
+        RehandshakeTest test = new RehandshakeTest();
+        setUpAndStartKDCIfNeeded();
+        test.runTests();
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.REHANDSHAKE_BEGIN_CLIENT);
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.REHANDSHAKE_BEGIN_SERVER);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/RehandshakeWithCipherChangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2017, 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import java.util.Random;
+import jdk.test.lib.RandomFactory;
+
+/**
+ * Testing SSLEngines re-handshaking with cipher change. New cipher is taken
+ * randomly from the supported ciphers list.
+ */
+public class RehandshakeWithCipherChangeTest extends SSLEngineTestCase {
+
+    public static void main(String[] s) {
+        RehandshakeWithCipherChangeTest test
+                = new RehandshakeWithCipherChangeTest();
+        test.runTests(Ciphers.ENABLED_NON_KRB_NOT_ANON_CIPHERS);
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        SSLEngine clientEngine = context.createSSLEngine();
+        clientEngine.setUseClientMode(true);
+        SSLEngine serverEngine = context.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(
+                Ciphers.ENABLED_NON_KRB_NOT_ANON_CIPHERS.ciphers);
+        String randomCipher;
+        serverEngine.setNeedClientAuth(true);
+        long initialEpoch = 0;
+        long secondEpoch = 0;
+        SSLEngineResult r;
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+        sendApplicationData(clientEngine, serverEngine);
+        r = sendApplicationData(serverEngine, clientEngine);
+        if (TESTED_SECURITY_PROTOCOL.contains("DTLS")) {
+            initialEpoch = r.sequenceNumber() >> 48;
+        }
+        final Random RNG = RandomFactory.getRandom();
+        randomCipher = Ciphers.ENABLED_NON_KRB_NOT_ANON_CIPHERS.ciphers[RNG
+                .nextInt(Ciphers.ENABLED_NON_KRB_NOT_ANON_CIPHERS.ciphers.length)];
+        clientEngine.setEnabledCipherSuites(new String[]{randomCipher});
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.REHANDSHAKE_BEGIN_CLIENT);
+        sendApplicationData(clientEngine, serverEngine);
+        r = sendApplicationData(serverEngine, clientEngine);
+        if (TESTED_SECURITY_PROTOCOL.contains("DTLS")) {
+            secondEpoch = r.sequenceNumber() >> 48;
+            AssertionError epochError = new AssertionError("Epoch number"
+                    + " did not grow after re-handshake! "
+                    + " Was " + initialEpoch + ", now " + secondEpoch + ".");
+            if (Long.compareUnsigned(secondEpoch, initialEpoch) <= 0) {
+                throw epochError;
+            }
+        }
+        closeEngines(clientEngine, serverEngine);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/RehandshakeWithDataExTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+
+/**
+ * Testing SSLEngines re-handshaking using each of the supported cipher suites
+ * with application data exchange before and after re-handshake and closing of
+ * the engines.
+ */
+public class RehandshakeWithDataExTest extends SSLEngineTestCase {
+
+    public static void main(String[] args) {
+        RehandshakeWithDataExTest test = new RehandshakeWithDataExTest();
+        setUpAndStartKDCIfNeeded();
+        test.runTests();
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) throws SSLException {
+        SSLContext context = getContext();
+        int maxPacketSize = getMaxPacketSize();
+        boolean useSNI = !TEST_MODE.equals("norm");
+        SSLEngine clientEngine = getClientSSLEngine(context, useSNI);
+        SSLEngine serverEngine = getServerSSLEngine(context, useSNI);
+        clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        serverEngine.setNeedClientAuth(!cipher.contains("anon"));
+        long initialEpoch = 0;
+        long secondEpoch = 0;
+        long thirdEpoch = 0;
+        SSLEngineResult r;
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.INITIAL_HANDSHAKE);
+        sendApplicationData(clientEngine, serverEngine);
+        r = sendApplicationData(serverEngine, clientEngine);
+        if (TESTED_SECURITY_PROTOCOL.contains("DTLS")) {
+            initialEpoch = r.sequenceNumber() >> 48;
+        }
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.REHANDSHAKE_BEGIN_CLIENT);
+        sendApplicationData(clientEngine, serverEngine);
+        r = sendApplicationData(serverEngine, clientEngine);
+        AssertionError epochError = new AssertionError("Epoch number"
+                + " did not grow after re-handshake! "
+                + " Was " + initialEpoch + ", now " + secondEpoch + ".");
+        if (TESTED_SECURITY_PROTOCOL.contains("DTLS")) {
+            secondEpoch = r.sequenceNumber() >> 48;
+            if (Long.compareUnsigned(secondEpoch, initialEpoch) <= 0) {
+                throw epochError;
+            }
+        }
+        doHandshake(clientEngine, serverEngine, maxPacketSize,
+                HandshakeMode.REHANDSHAKE_BEGIN_SERVER);
+        sendApplicationData(clientEngine, serverEngine);
+        r = sendApplicationData(serverEngine, clientEngine);
+        if (TESTED_SECURITY_PROTOCOL.contains("DTLS")) {
+        thirdEpoch = r.sequenceNumber() >> 48;
+            if (Long.compareUnsigned(thirdEpoch, secondEpoch) <= 0) {
+                throw epochError;
+            }
+        }
+        closeEngines(clientEngine, serverEngine);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/SSLEngineTestCase.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (c) 2015, 2018, 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Basic class to inherit SSLEngine test cases from it. Tests apply for
+ * the TLS or DTLS security protocols and their versions.
+ */
+abstract public class SSLEngineTestCase {
+
+    public enum Ciphers {
+
+        /**
+         * Ciphers supported by the tested SSLEngine without those with
+         * kerberos authentication.
+         */
+        SUPPORTED_NON_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_NON_KRB_CIPHERS,
+                "Supported non kerberos"),
+        /**
+         * Ciphers supported by the tested SSLEngine without those with
+         * kerberos authentication and without those with SHA256 ans SHA384.
+         */
+        SUPPORTED_NON_KRB_NON_SHA_CIPHERS(
+                SSLEngineTestCase.SUPPORTED_NON_KRB_NON_SHA_CIPHERS,
+                "Supported non kerberos non SHA256 and SHA384"),
+        /**
+         * Ciphers supported by the tested SSLEngine with kerberos
+         * authentication.
+         */
+        SUPPORTED_KRB_CIPHERS(SSLEngineTestCase.SUPPORTED_KRB_CIPHERS,
+                "Supported kerberos"),
+        /**
+         * Ciphers enabled by default for the tested SSLEngine without kerberos
+         * and anon.
+         */
+        ENABLED_NON_KRB_NOT_ANON_CIPHERS(
+                SSLEngineTestCase.ENABLED_NON_KRB_NOT_ANON_CIPHERS,
+                "Enabled by default non kerberos not anonymous"),
+        /**
+         * Ciphers supported by TLS 1.3 only.
+         */
+        TLS13_CIPHERS(
+                SSLEngineTestCase.TLS13_CIPHERS,
+                "Supported by TLS 1.3 only"),
+        /**
+         * Ciphers unsupported by the tested SSLEngine.
+         */
+        UNSUPPORTED_CIPHERS(SSLEngineTestCase.UNSUPPORTED_CIPHERS,
+                "Unsupported");
+
+        Ciphers(String[] ciphers, String description) {
+            this.ciphers = ciphers;
+            this.description = description;
+        }
+
+        final String[] ciphers;
+        final String description;
+    }
+
+    /**
+     * Enumeration used to distinguish handshake mode in
+     * {@link SSLEngineTestCase#doHandshake(javax.net.ssl.SSLEngine,
+     * javax.net.ssl.SSLEngine, int, SSLEngineTestCase.HandshakeMode, boolean)
+     * SSLEngineTestCase.doHandshake} method.
+     */
+    public enum HandshakeMode {
+
+        /**
+         * Initial handshake done for the first time: both engines call
+         * {@link SSLEngine#beginHandshake()} method.
+         */
+        INITIAL_HANDSHAKE,
+        /**
+         * Repeated handshake done by client: client engine calls
+         * {@link SSLEngine#beginHandshake()} method.
+         */
+        REHANDSHAKE_BEGIN_CLIENT,
+        /**
+         * Repeated handshake done by server: server engine calls
+         * {@link SSLEngine#beginHandshake()} method.
+         */
+        REHANDSHAKE_BEGIN_SERVER;
+    }
+    /**
+     * Security protocol to be tested: "TLS" or "DTLS" or their versions,
+     * e.g. "TLSv1", "TLSv1.1", "TLSv1.2", "DTLSv1.0", "DTLSv1.2".
+     */
+    public static final String TESTED_SECURITY_PROTOCOL
+            = System.getProperty("test.security.protocol", "TLS");
+    /**
+     * Test mode: "norm", "norm_sni" or "krb".
+     * Modes "norm" and "norm_sni" are used to run
+     * with all supported non-kerberos ciphers.
+     * Mode "krb" is used to run with kerberos ciphers.
+     */
+    public static final String TEST_MODE
+            = System.getProperty("test.mode", "norm");
+
+    private static final String FS = System.getProperty("file.separator", "/");
+    private static final String PATH_TO_STORES = ".." + FS + "etc";
+    private static final String KEY_STORE_FILE = "keystore";
+    private static final String TRUST_STORE_FILE = "truststore";
+    private static final String PASSWD = "passphrase";
+
+    private static final String KEY_FILE_NAME
+            = System.getProperty("test.src", ".") + FS + PATH_TO_STORES
+            + FS + KEY_STORE_FILE;
+    private static final String TRUST_FILE_NAME
+            = System.getProperty("test.src", ".") + FS + PATH_TO_STORES
+            + FS + TRUST_STORE_FILE;
+
+    // Need an enhancement to use none-static mutable global variables.
+    private static ByteBuffer net;
+    private static boolean doUnwrapForNotHandshakingStatus;
+    private static boolean endHandshakeLoop = false;
+
+    private static final int MAX_HANDSHAKE_LOOPS = 100;
+    private static final String EXCHANGE_MSG_SENT = "Hello, peer!";
+    private static final String TEST_SRC = System.getProperty("test.src", ".");
+    private static final String KTAB_FILENAME = "krb5.keytab.data";
+    private static final String KRB_REALM = "TEST.REALM";
+    private static final String KRBTGT_PRINCIPAL = "krbtgt/" + KRB_REALM;
+    private static final String KRB_USER = "USER";
+    private static final String KRB_USER_PASSWORD = "password";
+    private static final String KRB_USER_PRINCIPAL = KRB_USER + "@" + KRB_REALM;
+    private static final String KRB5_CONF_FILENAME = "krb5.conf";
+    private static final String PATH_TO_COMMON = ".." + FS + "TLSCommon";
+    private static final String JAAS_CONF_FILE = PATH_TO_COMMON
+            + FS + "jaas.conf";
+    private static final int DELAY = 1000;
+    private static final String HOST = "localhost";
+    private static final String SERVER_NAME = "service.localhost";
+    private static final String SNI_PATTERN = ".*";
+
+    private static final String[] TLS13_CIPHERS = {
+            "TLS_AES_256_GCM_SHA384",
+            "TLS_AES_128_GCM_SHA256"
+    };
+
+    private static final String[] SUPPORTED_NON_KRB_CIPHERS;
+
+    static {
+        try {
+            String[] allSupportedCiphers = getContext()
+                    .createSSLEngine().getSupportedCipherSuites();
+            List<String> supportedCiphersList = new LinkedList<>();
+            for (String cipher : allSupportedCiphers) {
+                if (!cipher.contains("KRB5")
+                        && !isTLS13Cipher(cipher)
+                        && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
+                    supportedCiphersList.add(cipher);
+                }
+            }
+            SUPPORTED_NON_KRB_CIPHERS =
+                    supportedCiphersList.toArray(new String[0]);
+        } catch (Exception ex) {
+            throw new Error("Unexpected issue", ex);
+        }
+    }
+
+    private static final String[] SUPPORTED_NON_KRB_NON_SHA_CIPHERS;
+
+    static {
+        try {
+            String[] allSupportedCiphers = getContext()
+                    .createSSLEngine().getSupportedCipherSuites();
+            List<String> supportedCiphersList = new LinkedList<>();
+            for (String cipher : allSupportedCiphers) {
+                if (!cipher.contains("KRB5")
+                        && !isTLS13Cipher(cipher)
+                        && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")
+                        && !cipher.endsWith("_SHA256")
+                        && !cipher.endsWith("_SHA384")) {
+                    supportedCiphersList.add(cipher);
+                }
+            }
+            SUPPORTED_NON_KRB_NON_SHA_CIPHERS
+                    = supportedCiphersList.toArray(new String[0]);
+        } catch (Exception ex) {
+            throw new Error("Unexpected issue", ex);
+        }
+    }
+
+    private static final String[] SUPPORTED_KRB_CIPHERS;
+
+    static {
+        try {
+            String[] allSupportedCiphers = getContext()
+                    .createSSLEngine().getSupportedCipherSuites();
+            List<String> supportedCiphersList = new LinkedList<>();
+            for (String cipher : allSupportedCiphers) {
+                if (cipher.contains("KRB5")
+                        && !isTLS13Cipher(cipher)
+                        && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
+                    supportedCiphersList.add(cipher);
+                }
+            }
+            SUPPORTED_KRB_CIPHERS = supportedCiphersList.toArray(new String[0]);
+        } catch (Exception ex) {
+            throw new Error("Unexpected issue", ex);
+        }
+    }
+
+    private static final String[] ENABLED_NON_KRB_NOT_ANON_CIPHERS;
+
+    static {
+        try {
+            SSLEngine temporary = getContext().createSSLEngine();
+            temporary.setUseClientMode(true);
+            String[] enabledCiphers = temporary.getEnabledCipherSuites();
+            List<String> enabledCiphersList = new LinkedList<>();
+            for (String cipher : enabledCiphers) {
+                if (!cipher.contains("anon") && !cipher.contains("KRB5")
+                        && !isTLS13Cipher(cipher)
+                        && !cipher.contains("TLS_EMPTY_RENEGOTIATION_INFO_SCSV")) {
+                    enabledCiphersList.add(cipher);
+                }
+            }
+            ENABLED_NON_KRB_NOT_ANON_CIPHERS =
+                    enabledCiphersList.toArray(new String[0]);
+        } catch (Exception ex) {
+            throw new Error("Unexpected issue", ex);
+        }
+    }
+
+    private static final String[] UNSUPPORTED_CIPHERS = {
+            "SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA",
+            "SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA",
+            "SSL_DHE_DSS_WITH_RC4_128_SHA",
+            "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
+            "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA",
+            "SSL_DH_DSS_WITH_DES_CBC_SHA",
+            "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
+            "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA",
+            "SSL_DH_RSA_WITH_DES_CBC_SHA",
+            "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",
+            "SSL_FORTEZZA_DMS_WITH_NULL_SHA",
+            "SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",
+            "SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",
+            "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+            "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA",
+            "SSL_RSA_FIPS_WITH_DES_CBC_SHA",
+            "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
+            "TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
+            "TLS_KRB5_WITH_IDEA_CBC_MD5",
+            "TLS_KRB5_WITH_IDEA_CBC_SHA",
+            "SSL_RSA_WITH_IDEA_CBC_SHA",
+            "TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
+            "TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
+            "TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
+            "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"
+    };
+
+    private final int maxPacketSize;
+
+    /**
+     * Constructs test case with the given MFLN maxMacketSize.
+     *
+     * @param maxPacketSize - MLFN extension max packet size.
+     */
+    public SSLEngineTestCase(int maxPacketSize) {
+        this.maxPacketSize = maxPacketSize;
+    }
+
+    /**
+     * Constructs test case with {@code maxPacketSize = 0}.
+     */
+    public SSLEngineTestCase() {
+        this.maxPacketSize = 0;
+    }
+
+    private static boolean isTLS13Cipher(String cipher) {
+        for (String cipherSuite : TLS13_CIPHERS) {
+            if (cipherSuite.equals(cipher)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Wraps data with the specified engine.
+     *
+     * @param engine        - SSLEngine that wraps data.
+     * @param wrapper       - Set wrapper id, e.g. "server" of "client".
+     *                        Used for logging only.
+     * @param maxPacketSize - Max packet size to check that MFLN extension
+     *                        works or zero for no check.
+     * @param app           - Buffer with data to wrap.
+     * @return - Buffer with wrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
+                                    int maxPacketSize, ByteBuffer app)
+            throws SSLException {
+        return doWrap(engine, wrapper, maxPacketSize,
+                app, SSLEngineResult.Status.OK, null);
+    }
+
+    /**
+     * Wraps data with the specified engine.
+     *
+     * @param engine        - SSLEngine that wraps data.
+     * @param wrapper       - Set wrapper id, e.g. "server" of "client".
+     *                        Used for logging only.
+     * @param maxPacketSize - Max packet size to check that MFLN extension
+     *                        works or zero for no check.
+     * @param app           - Buffer with data to wrap.
+     * @param result        - Array which first element will be used to
+     *                        output wrap result object.
+     * @return - Buffer with wrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
+                                    int maxPacketSize, ByteBuffer app,
+                                    SSLEngineResult[] result)
+            throws SSLException {
+        return doWrap(engine, wrapper, maxPacketSize,
+                app, SSLEngineResult.Status.OK, result);
+    }
+
+    /**
+     * Wraps data with the specified engine.
+     *
+     * @param engine        - SSLEngine that wraps data.
+     * @param wrapper       - Set wrapper id, e.g. "server" of "client".
+     *                        Used for logging only.
+     * @param maxPacketSize - Max packet size to check that MFLN extension
+     *                        works or zero for no check.
+     * @param app           - Buffer with data to wrap.
+     * @param wantedStatus  - Specifies expected result status of wrapping.
+     * @return - Buffer with wrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
+                                    int maxPacketSize, ByteBuffer app,
+                                    SSLEngineResult.Status wantedStatus)
+            throws SSLException {
+        return doWrap(engine, wrapper, maxPacketSize,
+                app, wantedStatus, null);
+    }
+
+    /**
+     * Wraps data with the specified engine.
+     *
+     * @param engine        - SSLEngine that wraps data.
+     * @param wrapper       - Set wrapper id, e.g. "server" of "client".
+     *                        Used for logging only.
+     * @param maxPacketSize - Max packet size to check that MFLN extension
+     *                        works or zero for no check.
+     * @param app           - Buffer with data to wrap.
+     * @param wantedStatus  - Specifies expected result status of wrapping.
+     * @param result        - Array which first element will be used to output
+     *                        wrap result object.
+     * @return - Buffer with wrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doWrap(SSLEngine engine, String wrapper,
+                                    int maxPacketSize, ByteBuffer app,
+                                    SSLEngineResult.Status wantedStatus,
+                                    SSLEngineResult[] result)
+            throws SSLException {
+        ByteBuffer net = ByteBuffer.allocate(engine.getSession()
+                .getPacketBufferSize());
+        SSLEngineResult r = engine.wrap(app, net);
+        net.flip();
+        int length = net.remaining();
+        System.out.println(wrapper + " wrapped " + length + " bytes.");
+        System.out.println(wrapper + " handshake status is "
+                + engine.getHandshakeStatus() + " Result is " + r.getStatus());
+        if (maxPacketSize < length && maxPacketSize != 0) {
+            throw new AssertionError("Handshake wrapped net buffer length "
+                    + length + " exceeds maximum packet size "
+                    + maxPacketSize);
+        }
+        checkResult(r, wantedStatus);
+        if (result != null && result.length > 0) {
+            result[0] = r;
+        }
+        return net;
+    }
+
+    /**
+     * Unwraps data with the specified engine.
+     *
+     * @param engine    - SSLEngine that unwraps data.
+     * @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for
+     *                  logging only.
+     * @param net       - Buffer with data to unwrap.
+     * @return - Buffer with unwrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
+            ByteBuffer net) throws SSLException {
+        return doUnWrap(engine, unwrapper,
+                net, SSLEngineResult.Status.OK, null);
+    }
+
+    /**
+     * Unwraps data with the specified engine.
+     *
+     * @param engine    - SSLEngine that unwraps data.
+     * @param unwrapper - Set unwrapper id, e.g. "server" of "client". Used for
+     *                  logging only.
+     * @param net       - Buffer with data to unwrap.
+     * @param result    - Array which first element will be used to output wrap
+     *                  result object.
+     * @return - Buffer with unwrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
+            ByteBuffer net, SSLEngineResult[] result) throws SSLException {
+        return doUnWrap(engine, unwrapper,
+                net, SSLEngineResult.Status.OK, result);
+    }
+
+    /**
+     * Unwraps data with the specified engine.
+     *
+     * @param engine       - SSLEngine that unwraps data.
+     * @param unwrapper    - Set unwrapper id, e.g. "server" of "client".
+     *                     Used for logging only.
+     * @param net          - Buffer with data to unwrap.
+     * @param wantedStatus - Specifies expected result status of wrapping.
+     * @return - Buffer with unwrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
+            ByteBuffer net,
+            SSLEngineResult.Status wantedStatus) throws SSLException {
+        return doUnWrap(engine, unwrapper, net, wantedStatus, null);
+    }
+
+    /**
+     * Unwraps data with the specified engine.
+     *
+     * @param engine       - SSLEngine that unwraps data.
+     * @param unwrapper    - Set unwrapper id, e.g. "server" of "client".
+     *                       Used for logging only.
+     * @param net          - Buffer with data to unwrap.
+     * @param wantedStatus - Specifies expected result status of wrapping.
+     * @param result       - Array which first element will be used to output
+     *                       wrap result object.
+     * @return - Buffer with unwrapped data.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static ByteBuffer doUnWrap(SSLEngine engine, String unwrapper,
+            ByteBuffer net, SSLEngineResult.Status wantedStatus,
+            SSLEngineResult[] result) throws SSLException {
+
+        ByteBuffer app = ByteBuffer.allocate(
+                engine.getSession().getApplicationBufferSize());
+        int length = net.remaining();
+        System.out.println(unwrapper + " unwrapping " + length + " bytes...");
+        SSLEngineResult r = engine.unwrap(net, app);
+        app.flip();
+        System.out.println(unwrapper + " handshake status is "
+                + engine.getHandshakeStatus() + " Result is " + r.getStatus());
+        checkResult(r, wantedStatus);
+        if (result != null && result.length > 0) {
+            result[0] = r;
+        }
+        return app;
+    }
+
+    /**
+     * Does the handshake of the two specified engines according to the
+     * {@code mode} specified.
+     *
+     * @param clientEngine  - Client SSLEngine.
+     * @param serverEngine  - Server SSLEngine.
+     * @param maxPacketSize - Maximum packet size for MFLN of zero for no limit.
+     * @param mode          - Handshake mode according to
+     *                        {@link HandshakeMode} enum.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static void doHandshake(SSLEngine clientEngine,
+        SSLEngine serverEngine,
+        int maxPacketSize, HandshakeMode mode) throws SSLException {
+
+        doHandshake(clientEngine, serverEngine, maxPacketSize, mode, false);
+    }
+
+    /**
+     * Does the handshake of the two specified engines according to the
+     * {@code mode} specified.
+     *
+     * @param clientEngine          - Client SSLEngine.
+     * @param serverEngine          - Server SSLEngine.
+     * @param maxPacketSize         - Maximum packet size for MFLN of zero
+     *                                for no limit.
+     * @param mode                  - Handshake mode according to
+     *                                {@link HandshakeMode} enum.
+     * @param enableReplicatedPacks - Set {@code true} to enable replicated
+     *                                packet sending.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static void doHandshake(SSLEngine clientEngine,
+            SSLEngine serverEngine, int maxPacketSize,
+            HandshakeMode mode,
+            boolean enableReplicatedPacks) throws SSLException {
+
+        System.out.println("=============================================");
+        System.out.println("Starting handshake " + mode.name());
+        int loop = 0;
+        if (maxPacketSize < 0) {
+            throw new Error("Test issue: maxPacketSize is less than zero!");
+        }
+        SSLParameters params = clientEngine.getSSLParameters();
+        params.setMaximumPacketSize(maxPacketSize);
+        clientEngine.setSSLParameters(params);
+        params = serverEngine.getSSLParameters();
+        params.setMaximumPacketSize(maxPacketSize);
+        serverEngine.setSSLParameters(params);
+        SSLEngine firstEngine;
+        SSLEngine secondEngine;
+        switch (mode) {
+            case INITIAL_HANDSHAKE:
+                firstEngine = clientEngine;
+                secondEngine = serverEngine;
+                doUnwrapForNotHandshakingStatus = false;
+                clientEngine.beginHandshake();
+                serverEngine.beginHandshake();
+                break;
+            case REHANDSHAKE_BEGIN_CLIENT:
+                firstEngine = clientEngine;
+                secondEngine = serverEngine;
+                doUnwrapForNotHandshakingStatus = true;
+                clientEngine.beginHandshake();
+                break;
+            case REHANDSHAKE_BEGIN_SERVER:
+                firstEngine = serverEngine;
+                secondEngine = clientEngine;
+                doUnwrapForNotHandshakingStatus = true;
+                serverEngine.beginHandshake();
+                break;
+            default:
+                throw new Error("Test issue: unknown handshake mode");
+        }
+        endHandshakeLoop = false;
+        while (!endHandshakeLoop) {
+            if (++loop > MAX_HANDSHAKE_LOOPS) {
+                throw new Error("Too much loops for handshaking");
+            }
+            System.out.println("============================================");
+            System.out.println("Handshake loop " + loop + ": round 1");
+            System.out.println("==========================");
+            handshakeProcess(firstEngine, secondEngine, maxPacketSize,
+                    enableReplicatedPacks);
+            if (endHandshakeLoop) {
+                break;
+            }
+            System.out.println("Handshake loop " + loop + ": round 2");
+            System.out.println("==========================");
+            handshakeProcess(secondEngine, firstEngine, maxPacketSize,
+                    enableReplicatedPacks);
+        }
+    }
+
+    /**
+     * Routine to send application data from one SSLEngine to another.
+     *
+     * @param fromEngine - Sending engine.
+     * @param toEngine   - Receiving engine.
+     * @return - Result of unwrap method of the receiving engine.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static SSLEngineResult sendApplicationData(SSLEngine fromEngine,
+                                                      SSLEngine toEngine)
+            throws SSLException {
+        String sender = null;
+        String reciever = null;
+        String excMsgSent = EXCHANGE_MSG_SENT;
+        if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {
+            sender = "Client";
+            reciever = "Server";
+            excMsgSent += " Client.";
+        } else if (toEngine.getUseClientMode() &&
+                !fromEngine.getUseClientMode()) {
+            sender = "Server";
+            reciever = "Client";
+            excMsgSent += " Server.";
+        } else {
+            throw new Error("Test issue: both engines are in the same mode");
+        }
+        System.out.println("=============================================");
+        System.out.println("Trying to send application data from " + sender
+                + " to " + reciever);
+        ByteBuffer clientAppSent
+                = ByteBuffer.wrap(excMsgSent.getBytes());
+        net = doWrap(fromEngine, sender, 0, clientAppSent);
+        SSLEngineResult[] r = new SSLEngineResult[1];
+        ByteBuffer serverAppRecv = doUnWrap(toEngine, reciever, net, r);
+        byte[] serverAppRecvTrunc = Arrays.copyOf(serverAppRecv.array(),
+                serverAppRecv.limit());
+        String msgRecv = new String(serverAppRecvTrunc);
+        if (!msgRecv.equals(excMsgSent)) {
+            throw new AssertionError(sender + " to " + reciever
+                    + ": application data"
+                    + " has been altered while sending."
+                    + " Message sent: " + "\"" + excMsgSent + "\"."
+                    + " Message recieved: " + "\"" + msgRecv + "\".");
+        }
+        System.out.println("Successful sending application data from " + sender
+                + " to " + reciever);
+        return r[0];
+    }
+
+    /**
+     * Close engines by sending "close outbound" message from one SSLEngine to
+     * another.
+     *
+     * @param fromEngine - Sending engine.
+     * @param toEngine   - Receiving engine.
+     * @throws SSLException - thrown on engine errors.
+     */
+    public static void closeEngines(SSLEngine fromEngine,
+                                    SSLEngine toEngine) throws SSLException {
+        String from = null;
+        String to = null;
+        ByteBuffer app;
+        if (fromEngine.getUseClientMode() && !toEngine.getUseClientMode()) {
+            from = "Client";
+            to = "Server";
+        } else if (toEngine.getUseClientMode() &&
+                !fromEngine.getUseClientMode()) {
+            from = "Server";
+            to = "Client";
+        } else {
+            throw new Error("Both engines are in the same mode");
+        }
+        System.out.println("=============================================");
+        System.out.println(
+                "Trying to close engines from " + from + " to " + to);
+        // Sending close outbound request to peer
+        fromEngine.closeOutbound();
+        app = ByteBuffer.allocate(
+                fromEngine.getSession().getApplicationBufferSize());
+        net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
+        doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
+        app = ByteBuffer.allocate(
+                fromEngine.getSession().getApplicationBufferSize());
+        net = doWrap(toEngine, to, 0, app, SSLEngineResult.Status.CLOSED);
+        doUnWrap(fromEngine, from, net, SSLEngineResult.Status.CLOSED);
+        if (!toEngine.isInboundDone()) {
+            throw new AssertionError(from + " sent close request to " + to
+                    + ", but " + to + "did not close inbound.");
+        }
+        // Executing close inbound
+        fromEngine.closeInbound();
+        app = ByteBuffer.allocate(
+                fromEngine.getSession().getApplicationBufferSize());
+        net = doWrap(fromEngine, from, 0, app, SSLEngineResult.Status.CLOSED);
+        doUnWrap(toEngine, to, net, SSLEngineResult.Status.CLOSED);
+        if (!toEngine.isOutboundDone()) {
+            throw new AssertionError(from + "sent close request to " + to
+                    + ", but " + to + "did not close outbound.");
+        }
+        System.out.println("Successful closing from " + from + " to " + to);
+    }
+
+    /**
+     * Runs the same test case for all given {@code ciphers}. Method counts all
+     * failures and throws {@code AssertionError} if one or more tests fail.
+     *
+     * @param ciphers - Ciphers that should be tested.
+     */
+    public void runTests(Ciphers ciphers) {
+        int total = ciphers.ciphers.length;
+        int failed = testSomeCiphers(ciphers);
+        if (failed > 0) {
+            throw new AssertionError("" + failed + " of " + total
+                    + " tests failed!");
+        }
+        System.out.println("All tests passed!");
+    }
+
+    /**
+     * Runs test cases for ciphers defined by the test mode.
+     */
+    public void runTests() {
+        switch (TEST_MODE) {
+            case "norm":
+            case "norm_sni":
+                switch (TESTED_SECURITY_PROTOCOL) {
+                    case "DTLSv1.0":
+                    case "TLSv1":
+                    case "TLSv1.1":
+                        runTests(Ciphers.SUPPORTED_NON_KRB_NON_SHA_CIPHERS);
+                        break;
+                    case "DTLSv1.1":
+                    case "TLSv1.2":
+                        runTests(Ciphers.SUPPORTED_NON_KRB_CIPHERS);
+                        break;
+                    case "TLSv1.3":
+                        runTests(Ciphers.TLS13_CIPHERS);
+                        break;
+                }
+                break;
+            case "krb":
+                runTests(Ciphers.SUPPORTED_KRB_CIPHERS);
+                break;
+            default:
+                throw new Error(
+                        "Test error: unexpected test mode: " + TEST_MODE);
+        }
+    }
+
+    /**
+     * Returns maxPacketSize value used for MFLN extension testing
+     *
+     * @return - MLFN extension max packet size.
+     */
+    public int getMaxPacketSize() {
+        return maxPacketSize;
+    }
+
+    /**
+     * Checks that status of result {@code r} is {@code wantedStatus}.
+     *
+     * @param r            - Result.
+     * @param wantedStatus - Wanted status of the result.
+     * @throws AssertionError - if status or {@code r} is not
+     *                        {@code wantedStatus}.
+     */
+    public static void checkResult(SSLEngineResult r,
+                                   SSLEngineResult.Status wantedStatus) {
+        SSLEngineResult.Status rs = r.getStatus();
+        if (!rs.equals(wantedStatus)) {
+            throw new AssertionError("Unexpected status " + rs.name()
+                    + ", should be " + wantedStatus.name());
+        }
+    }
+
+    /**
+     * Returns SSLContext with TESTED_SECURITY_PROTOCOL protocol and
+     * sets up keys.
+     *
+     * @return - SSLContext with a protocol specified by
+     *           TESTED_SECURITY_PROTOCOL.
+     */
+    public static SSLContext getContext() {
+        try {
+            java.security.Security.setProperty(
+                    "jdk.tls.disabledAlgorithms", "");
+            java.security.Security.setProperty(
+                    "jdk.certpath.disabledAlgorithms", "");
+            KeyStore ks = KeyStore.getInstance("JKS");
+            KeyStore ts = KeyStore.getInstance("JKS");
+            char[] passphrase = PASSWD.toCharArray();
+            try (FileInputStream keyFileStream =
+                    new FileInputStream(KEY_FILE_NAME)) {
+                ks.load(keyFileStream, passphrase);
+            }
+            try (FileInputStream trustFileStream =
+                    new FileInputStream(TRUST_FILE_NAME)) {
+                ts.load(trustFileStream, passphrase);
+            }
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, passphrase);
+            TrustManagerFactory tmf =
+                    TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ts);
+            SSLContext sslCtx =
+                    SSLContext.getInstance(TESTED_SECURITY_PROTOCOL);
+            sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            return sslCtx;
+        } catch (KeyStoreException | IOException | NoSuchAlgorithmException |
+                CertificateException | UnrecoverableKeyException |
+                KeyManagementException ex) {
+            throw new Error("Unexpected exception", ex);
+        }
+    }
+
+    /**
+     * Sets up and starts kerberos KDC server.
+     */
+    public static void setUpAndStartKDC() {
+        String servicePrincipal = "host/" + SERVER_NAME + "@" + KRB_REALM;
+        Map<String, String> principals = new HashMap<>();
+        principals.put(KRB_USER_PRINCIPAL, KRB_USER_PASSWORD);
+        principals.put(KRBTGT_PRINCIPAL, null);
+        principals.put(servicePrincipal, null);
+        System.setProperty("java.security.krb5.conf", KRB5_CONF_FILENAME);
+        startKDC(KRB_REALM, principals, KTAB_FILENAME);
+        System.setProperty("java.security.auth.login.config",
+                TEST_SRC + FS + JAAS_CONF_FILE);
+        System.setProperty("javax.security.auth.useSubjectCredsOnly", "false");
+    }
+
+    /**
+     * Sets up and starts kerberos KDC server if
+     * SSLEngineTestCase.TEST_MODE is "krb".
+     */
+    public static void setUpAndStartKDCIfNeeded() {
+        if (TEST_MODE.equals("krb")) {
+            setUpAndStartKDC();
+        }
+    }
+
+    /**
+     * Returns client ssl engine.
+     *
+     * @param context - SSLContext to get SSLEngine from.
+     * @param useSNI  - flag used to enable or disable using SNI extension.
+     *                Needed for Kerberos.
+     */
+    public static SSLEngine getClientSSLEngine(
+            SSLContext context, boolean useSNI) {
+
+        SSLEngine clientEngine = context.createSSLEngine(HOST, 80);
+        clientEngine.setUseClientMode(true);
+        if (useSNI) {
+            SNIHostName serverName = new SNIHostName(SERVER_NAME);
+            List<SNIServerName> serverNames = new ArrayList<>();
+            serverNames.add(serverName);
+            SSLParameters params = clientEngine.getSSLParameters();
+            params.setServerNames(serverNames);
+            clientEngine.setSSLParameters(params);
+        }
+        return clientEngine;
+    }
+
+    /**
+     * Returns server ssl engine.
+     *
+     * @param context - SSLContext to get SSLEngine from.
+     * @param useSNI  - flag used to enable or disable using SNI extension.
+     *                Needed for Kerberos.
+     */
+    public static SSLEngine getServerSSLEngine(
+            SSLContext context, boolean useSNI) {
+
+        SSLEngine serverEngine = context.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        if (useSNI) {
+            SNIMatcher matcher = SNIHostName.createSNIMatcher(SNI_PATTERN);
+            List<SNIMatcher> matchers = new ArrayList<>();
+            matchers.add(matcher);
+            SSLParameters params = serverEngine.getSSLParameters();
+            params.setSNIMatchers(matchers);
+            serverEngine.setSSLParameters(params);
+        }
+        return serverEngine;
+    }
+
+    /**
+     * Runs the test case for one cipher suite.
+     *
+     * @param cipher - Cipher suite name.
+     * @throws SSLException - If tests fails.
+     */
+    abstract protected void testOneCipher(String cipher)
+            throws SSLException;
+
+    /**
+     * Iterates through an array of ciphers and runs the same test case for
+     * every entry.
+     *
+     * @param ciphers - Array of cipher names.
+     * @return - Number of tests failed.
+     */
+    protected int testSomeCiphers(Ciphers ciphers) {
+        int failedNum = 0;
+        String description = ciphers.description;
+        System.out.println("===============================================");
+        System.out.println(description + " ciphers testing");
+        System.out.println("===========================================");
+        for (String cs : ciphers.ciphers) {
+            System.out.println("---------------------------------------");
+            System.out.println("Testing cipher suite " + cs);
+            System.out.println("---------------------------------------");
+            Throwable error = null;
+
+            // Reset global mutable static variables
+            net = null;
+            doUnwrapForNotHandshakingStatus = false;
+            endHandshakeLoop = false;
+
+            try {
+                testOneCipher(cs);
+            } catch (Throwable t) {
+                error = t;
+            }
+            switch (ciphers) {
+                case SUPPORTED_NON_KRB_CIPHERS:
+                case SUPPORTED_NON_KRB_NON_SHA_CIPHERS:
+                case SUPPORTED_KRB_CIPHERS:
+                case ENABLED_NON_KRB_NOT_ANON_CIPHERS:
+                case TLS13_CIPHERS:
+                    if (error != null) {
+                        System.out.println("Test Failed: " + cs);
+                        System.err.println("Test Exception for " + cs);
+                        error.printStackTrace();
+                        failedNum++;
+                    } else {
+                        System.out.println("Test Passed: " + cs);
+                    }
+                    break;
+                case UNSUPPORTED_CIPHERS:
+                    if (error == null) {
+                        System.out.println("Test Failed: " + cs);
+                        System.err.println("Test for " + cs +
+                                " should have thrown " +
+                                "IllegalArgumentException, but it has not!");
+                        failedNum++;
+                    } else if (!(error instanceof IllegalArgumentException)) {
+                        System.out.println("Test Failed: " + cs);
+                        System.err.println("Test Exception for " + cs);
+                        error.printStackTrace();
+                        failedNum++;
+                    } else {
+                        System.out.println("Test Passed: " + cs);
+                    }
+                    break;
+                default:
+                    throw new Error("Test issue: unexpected ciphers: "
+                            + ciphers.name());
+            }
+        }
+
+        return failedNum;
+    }
+
+    /**
+     * Method used for the handshake routine.
+     *
+     * @param wrapingEngine         - Engine that is expected to wrap data.
+     * @param unwrapingEngine       - Engine that is expected to unwrap data.
+     * @param maxPacketSize         - Maximum packet size for MFLN of zero
+     *                                for no limit.
+     * @param enableReplicatedPacks - Set {@code true} to enable replicated
+     *                                packet sending.
+     * @throws SSLException - thrown on engine errors.
+     */
+    private static void handshakeProcess(SSLEngine wrapingEngine,
+            SSLEngine unwrapingEngine,
+            int maxPacketSize,
+            boolean enableReplicatedPacks) throws SSLException {
+
+        HandshakeStatus wrapingHSStatus = wrapingEngine.getHandshakeStatus();
+        HandshakeStatus unwrapingHSStatus =
+                unwrapingEngine.getHandshakeStatus();
+        SSLEngineResult r;
+        String wrapper, unwrapper;
+        if (wrapingEngine.getUseClientMode()
+                && !unwrapingEngine.getUseClientMode()) {
+            wrapper = "Client";
+            unwrapper = "Server";
+        } else if (unwrapingEngine.getUseClientMode()
+                && !wrapingEngine.getUseClientMode()) {
+            wrapper = "Server";
+            unwrapper = "Client";
+        } else {
+            throw new Error("Both engines are in the same mode");
+        }
+        System.out.println(
+                wrapper + " handshake (wrap) status " + wrapingHSStatus);
+        System.out.println(
+                unwrapper + " handshake (unwrap) status " + unwrapingHSStatus);
+
+        ByteBuffer netReplicatedClient = null;
+        ByteBuffer netReplicatedServer = null;
+        switch (wrapingHSStatus) {
+            case NEED_WRAP:
+                if (enableReplicatedPacks) {
+                    if (net != null) {
+                        net.flip();
+                        if (net.remaining() != 0) {
+                            if (wrapingEngine.getUseClientMode()) {
+                                netReplicatedServer = net;
+                            } else {
+                                netReplicatedClient = net;
+                            }
+                        }
+                    }
+                }
+                ByteBuffer app = ByteBuffer.allocate(
+                        wrapingEngine.getSession().getApplicationBufferSize());
+                net = doWrap(wrapingEngine, wrapper, maxPacketSize, app);
+                wrapingHSStatus = wrapingEngine.getHandshakeStatus();
+                // No break, falling into unwrapping.
+            case NOT_HANDSHAKING:
+                switch (unwrapingHSStatus) {
+                    case NEED_TASK:
+                        runDelegatedTasks(unwrapingEngine);
+                    case NEED_UNWRAP:
+                        doUnWrap(unwrapingEngine, unwrapper, net);
+                        if (enableReplicatedPacks) {
+                            System.out.println(unwrapper +
+                                    " unwrapping replicated packet...");
+                            if (unwrapingEngine.getHandshakeStatus()
+                                    .equals(HandshakeStatus.NEED_TASK)) {
+                                runDelegatedTasks(unwrapingEngine);
+                            }
+                            ByteBuffer netReplicated;
+                            if (unwrapingEngine.getUseClientMode()) {
+                                netReplicated = netReplicatedClient;
+                            } else {
+                                netReplicated = netReplicatedServer;
+                            }
+                            if (netReplicated != null) {
+                                doUnWrap(unwrapingEngine,
+                                        unwrapper, netReplicated);
+                            } else {
+                                net.flip();
+                                doUnWrap(unwrapingEngine, unwrapper, net);
+                            }
+                        }
+                        break;
+                    case NEED_UNWRAP_AGAIN:
+                        break;
+                    case NOT_HANDSHAKING:
+                        if (doUnwrapForNotHandshakingStatus) {
+                            System.out.println("Not handshake status unwrap");
+                            doUnWrap(unwrapingEngine, unwrapper, net);
+                            doUnwrapForNotHandshakingStatus = false;
+                            break;
+                        } else {
+                            if (wrapingHSStatus ==
+                                        HandshakeStatus.NOT_HANDSHAKING) {
+                                System.out.println("Handshake is completed");
+                                endHandshakeLoop = true;
+                            }
+                        }
+                        break;
+                    case NEED_WRAP:
+                        SSLSession session = unwrapingEngine.getSession();
+                        int bufferSize = session.getApplicationBufferSize();
+                        ByteBuffer b = ByteBuffer.allocate(bufferSize);
+                        net = doWrap(unwrapingEngine,
+                                        unwrapper, maxPacketSize, b);
+                        unwrapingHSStatus =
+                                unwrapingEngine.getHandshakeStatus();
+                        if ((wrapingHSStatus ==
+                                    HandshakeStatus.NOT_HANDSHAKING) &&
+                            (unwrapingHSStatus ==
+                                    HandshakeStatus.NOT_HANDSHAKING)) {
+
+                            System.out.println("Handshake is completed");
+                            endHandshakeLoop = true;
+                        }
+
+                        break;
+                    default:
+                        throw new Error(
+                                "Unexpected unwraping engine handshake status "
+                                + unwrapingHSStatus.name());
+                }
+                break;
+            case NEED_UNWRAP:
+                break;
+            case NEED_UNWRAP_AGAIN:
+                net.flip();
+                doUnWrap(wrapingEngine, wrapper, net);
+                break;
+            case NEED_TASK:
+                runDelegatedTasks(wrapingEngine);
+                break;
+            default:
+                throw new Error("Unexpected wraping engine handshake status "
+                        + wrapingHSStatus.name());
+        }
+    }
+
+    private static void runDelegatedTasks(SSLEngine engine) {
+        Runnable runnable;
+        System.out.println("Running delegated tasks...");
+        while ((runnable = engine.getDelegatedTask()) != null) {
+            runnable.run();
+        }
+        HandshakeStatus hs = engine.getHandshakeStatus();
+        if (hs == HandshakeStatus.NEED_TASK) {
+            throw new Error("Handshake shouldn't need additional tasks.");
+        }
+    }
+
+    /**
+     * Start a KDC server:
+     * - create a KDC instance
+     * - create Kerberos principals
+     * - save Kerberos configuration
+     * - save keys to keytab file
+     * - no pre-auth is required
+     */
+    private static void startKDC(String realm, Map<String, String> principals,
+                                 String ktab) {
+        try {
+            KDC kdc = KDC.create(realm, HOST, 0, true);
+            kdc.setOption(KDC.Option.PREAUTH_REQUIRED, Boolean.FALSE);
+            if (principals != null) {
+                principals.entrySet().stream().forEach((entry) -> {
+                    String name = entry.getKey();
+                    String password = entry.getValue();
+                    if (password == null || password.isEmpty()) {
+                        System.out.println("KDC: add a principal '" + name
+                                + "' with a random password");
+                        kdc.addPrincipalRandKey(name);
+                    } else {
+                        System.out.println("KDC: add a principal '" + name
+                                + "' with '" + password + "' password");
+                        kdc.addPrincipal(name, password.toCharArray());
+                    }
+                });
+            }
+            KDC.saveConfig(KRB5_CONF_FILENAME, kdc);
+            if (ktab != null) {
+                File ktabFile = new File(ktab);
+                if (ktabFile.exists()) {
+                    System.out.println("KDC: append keys to an exising "
+                            + "keytab file " + ktab);
+                    kdc.appendKtab(ktab);
+                } else {
+                    System.out.println("KDC: create a new keytab file "
+                            + ktab);
+                    kdc.writeKtab(ktab);
+                }
+            }
+            System.out.println("KDC: started on " + HOST + ":" + kdc.getPort()
+                    + " with '" + realm + "' realm");
+        } catch (Exception e) {
+            throw new RuntimeException("KDC: unexpected exception", e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/TLSTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,1245 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+/*
+ * @test
+ * @bug 8205111
+ * @summary Test TLS with different types of supported keys.
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha384 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha512 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 ec_rsa_pkcs1_sha256 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 ecdsa_sha1 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 ecdsa_secp384r1_sha384
+ *      TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 ecdsa_secp521r1_sha512
+ *      TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha256 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha384 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha512 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha256 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha384 TLS_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha512 TLS_AES_128_GCM_SHA256
+ *
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha1 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha256 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha384 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pkcs1_sha512 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 ec_rsa_pkcs1_sha256 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 ecdsa_sha1 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 ecdsa_secp384r1_sha384
+ *      TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 ecdsa_secp521r1_sha512
+ *      TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha256 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha384 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_rsae_sha512 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha256 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha384 TLS_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.3 rsa_pss_pss_sha512 TLS_AES_256_GCM_SHA384
+ *
+ * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha384
+ *      TLS_RSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.2 rsa_pkcs1_sha512
+ *      TLS_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.2 ec_rsa_pkcs1_sha256
+ *      TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm TLSTest TLSv1.2 ecdsa_sha1
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.2 ecdsa_secp384r1_sha384
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ * @run main/othervm TLSTest TLSv1.2 ecdsa_secp521r1_sha512
+ *      TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.2 rsa_pss_rsae_sha256
+ *      TLS_RSA_WITH_AES_256_CBC_SHA256
+ * @run main/othervm TLSTest TLSv1.2 rsa_pss_rsae_sha384
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.2 rsa_pss_rsae_sha512
+ *      TLS_RSA_WITH_AES_128_CBC_SHA256
+ * @run main/othervm TLSTest TLSv1.2 rsa_pss_pss_sha256
+ *      TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ * @run main/othervm TLSTest TLSv1.2 rsa_pss_pss_sha384
+ *      TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm TLSTest TLSv1.2 rsa_pss_pss_sha512
+ *      TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ *
+ * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha256
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha384
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.1 rsa_pkcs1_sha512
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.1 rsa_pss_rsae_sha256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.1 rsa_pss_rsae_sha384
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1.1 rsa_pss_rsae_sha512
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ *
+ * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha1 TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha256 TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha384 TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1 rsa_pkcs1_sha512 TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1 rsa_pss_rsae_sha256
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm TLSTest TLSv1 rsa_pss_rsae_sha384
+ *      TLS_RSA_WITH_AES_256_CBC_SHA
+ * @run main/othervm TLSTest TLSv1 rsa_pss_rsae_sha512
+ *      TLS_RSA_WITH_AES_128_CBC_SHA
+ */
+public class TLSTest {
+
+    private volatile static boolean clientRenegoReady = false;
+
+    public static void main(String[] args) throws Exception {
+
+        final String tlsProtocol = args[0];
+        final KeyType keyType = KeyType.valueOf(args[1]);
+        final String cipher = args[2];
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        CountDownLatch serverReady = new CountDownLatch(1);
+        Server server = new Server(tlsProtocol, keyType, cipher, serverReady);
+        server.start();
+
+        // Wait till server is ready to accept connection.
+        serverReady.await();
+        new Client(tlsProtocol, keyType, cipher, server.port).doClientSide();
+        if (server.serverExc != null) {
+            throw new RuntimeException(server.serverExc);
+        }
+    }
+
+    public static class Server implements Runnable {
+
+        private volatile int port = 0;
+        private final String tlsProtocol;
+        private final KeyType keyType;
+        private final String cipher;
+        private final CountDownLatch latch;
+        private volatile Exception serverExc;
+
+        public Server(String tlsProtocol, KeyType keyType, String cipher,
+                CountDownLatch latch) {
+            this.tlsProtocol = tlsProtocol;
+            this.keyType = keyType;
+            this.cipher = cipher;
+            this.latch = latch;
+        }
+
+        public void start() {
+
+            ExecutorService executor = null;
+            try {
+                executor = Executors.newCachedThreadPool(new ThreadFactory() {
+                    @Override
+                    public Thread newThread(Runnable r) {
+                        Thread t = Executors.defaultThreadFactory()
+                                .newThread(r);
+                        t.setDaemon(true);
+                        return t;
+                    }
+                });
+                executor.execute(this);
+            } finally {
+                if (executor != null) {
+                    executor.shutdown();
+                }
+            }
+        }
+
+        /*
+         * Define the server side operation.
+         */
+        void doServerSide() throws Exception {
+
+            SSLContext ctx = getSSLContext(tlsProtocol,
+                    keyType.getTrustedCert(), keyType.getEndCert(),
+                    keyType.getPrivateKey(), keyType.getKeyType());
+            SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
+            SSLServerSocket sslServerSocket
+                    = (SSLServerSocket) sslssf.createServerSocket(port);
+            port = sslServerSocket.getLocalPort();
+            System.out.println("Server listining on port: " + port);
+            // specify the enabled server cipher suites
+            sslServerSocket.setEnabledCipherSuites(new String[]{this.cipher});
+            sslServerSocket.setEnabledProtocols(new String[]{tlsProtocol});
+            sslServerSocket.setSoTimeout(25000);
+            /*
+             * Signal Client, the server is ready to accept client request.
+             */
+            latch.countDown();
+            try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept()) {
+                try (InputStream sslIS = sslSocket.getInputStream();
+                        OutputStream sslOS = sslSocket.getOutputStream();) {
+                    sslIS.read();
+                    sslOS.write(85);
+                    sslOS.flush();
+                    while (!clientRenegoReady) {
+                        System.out.println("Waiting for ClientHello");
+                        TimeUnit.MILLISECONDS.sleep(50);
+                    }
+                    for (int i = 0; i < 4; i++) {
+                        sslIS.read();
+                        sslOS.write(89);
+                        sslOS.flush();
+                        TimeUnit.MILLISECONDS.sleep(50);   // wait for a while
+                    }
+                }
+            } finally {
+                sslServerSocket.close();
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                // Print the exception for debug purpose.
+                e.printStackTrace(System.out);
+                serverExc = e;
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    public static class Client {
+
+        private final int serverPort;
+        private final String tlsProtocol;
+        private final KeyType keyType;
+        private final String cipher;
+
+        public Client(String tlsProtocol, KeyType keyType, String cipher,
+                int serverPort) {
+            this.tlsProtocol = tlsProtocol;
+            this.keyType = keyType;
+            this.cipher = cipher;
+            this.serverPort = serverPort;
+        }
+
+        void doClientSide() throws Exception {
+
+            SSLContext ctx = getSSLContext(this.tlsProtocol,
+                    keyType.getTrustedCert(), null, null, keyType.getKeyType());
+            SSLSocketFactory sslsf = ctx.getSocketFactory();
+            try (SSLSocket sslSocket
+                    = (SSLSocket) sslsf.createSocket("localhost", serverPort)) {
+                // Specify the client cipher suites
+                sslSocket.setEnabledCipherSuites(new String[]{this.cipher});
+                sslSocket.setEnabledProtocols(new String[]{this.tlsProtocol});
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+                try {
+                    sslOS.write(86);
+                    sslOS.flush();
+                    sslIS.read();
+                    // Re-handshake for key-update and session resumption.
+                    sslSocket.startHandshake();
+                    System.out.println("Client: Re-Handshake completed.");
+                } finally {
+                    clientRenegoReady = true;
+                }
+                try {
+                    for (int i = 0; i < 4; i++) {
+                        sslOS.write(88);
+                        sslOS.flush();
+                        sslIS.read();
+                        TimeUnit.MILLISECONDS.sleep(50);  // wait for a while
+                    }
+                } finally {
+                    sslIS.close();
+                    sslOS.close();
+                }
+            }
+        }
+    }
+
+    // get the ssl context
+    protected static SSLContext getSSLContext(String tlsProtocol,
+            String trustedCertStr, String keyCertStr,
+            String privateKey, String keyType) throws Exception {
+
+        // Generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // Create a key store
+        KeyStore ts = KeyStore.getInstance("PKCS12");
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+        ts.load(null, null);
+        ks.load(null, null);
+        char passphrase[] = "passphrase".toCharArray();
+
+        // Import the trusted cert
+        ts.setCertificateEntry("trusted-cert-" + keyType,
+                cf.generateCertificate(new ByteArrayInputStream(
+                        trustedCertStr.getBytes())));
+
+        boolean hasKeyMaterials = keyCertStr != null && privateKey != null;
+        if (hasKeyMaterials) {
+
+            // Generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(privateKey));
+            KeyFactory kf = KeyFactory.getInstance(keyType);
+            PrivateKey priKey = kf.generatePrivate(priKeySpec);
+
+            // Generate certificate chain
+            Certificate keyCert = cf.generateCertificate(
+                    new ByteArrayInputStream(keyCertStr.getBytes()));
+            Certificate[] chain = new Certificate[]{keyCert};
+
+            // Import the key entry.
+            ks.setKeyEntry("cert-" + keyType, priKey, passphrase, chain);
+        }
+
+        // Create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ts);
+
+        SSLContext context = SSLContext.getInstance(tlsProtocol);
+        if (hasKeyMaterials) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            context.init(null, tmf.getTrustManagers(), null);
+        }
+        return context;
+    }
+
+    enum KeyType {
+
+        ec_rsa_pkcs1_sha256(
+                "EC",
+                /**
+                 * Signature Algorithm: sha256WithRSAEncryption
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 5 07:20:59 2018 GMT
+                 * Not After : May 31 07:20:59 2038 GMT
+                 * Subject: CN = root
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIC/DCCAeSgAwIBAgIUDJ+blgr9+e9ezH0Cj/NZ1Skd8GQwDQYJKoZIhvcNAQEL\n"
+                + "BQAwDzENMAsGA1UEAwwEcm9vdDAeFw0xODA2MDUwNzIwNTlaFw0zODA1MzEwNzIw\n"
+                + "NTlaMA8xDTALBgNVBAMMBHJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n"
+                + "AoIBAQDV48Mrbx+kWa1h/M2+Unr4AZM2raONrmwixJmosoiy+wOfjGfcwZyEyvNm\n"
+                + "FzVor3klBJLAam/4ndgyytFmCvaUT9oLm9N99dViSL2Tn388bWFFmMngsmGlFLMD\n"
+                + "fTsuBvxsYedyFUAgnpqLQCBiGrX930LF4bexegiBUftEK6lTbuq98vKW6bHT+B+o\n"
+                + "jkd23zYC7yBo9hgSuoDpI4s8lGh6vwAiijybaVve8t/idWHXWqk9mLJ//j5rj39F\n"
+                + "PYjDg7LF8xFV7nP7q/6KK0XBQdUMpmrShC/hE4BoUPks0dOEjAh+nN4O1J/4xlYX\n"
+                + "O5oaPVtvi3LJdjQvTQA7mEyM02ClAgMBAAGjUDBOMB0GA1UdDgQWBBTwyBBY7sOc\n"
+                + "sEdvYf7oRvf7MIIsjTAfBgNVHSMEGDAWgBTwyBBY7sOcsEdvYf7oRvf7MIIsjTAM\n"
+                + "BgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQC6CnR4XWQ4uO2H5Ngt+4Yk\n"
+                + "V82+oBlxa9SMK/tt67YC7wsxALsYqQ8oj3sGhH6mlNv2gDQ/OOC/HcdI/N72s+/n\n"
+                + "HnWq7vInx2M5P0QCRXjTUxx4+OPdH11zbsK5ZkE0SCOwlzlkcqU1fkwbr+vovgcP\n"
+                + "HgYL+3eGlNcz6+XwtVfySDbRkLYGbLlG1dH5WqR9+Z7glRgl6D+ZdOxEAwhbCAu1\n"
+                + "ADGGckA4107gVrR2r8YvzS/cO9Q97XWEXlfeHs5t7TQSJdNg6Gep1jLpFEQ98h/c\n"
+                + "y4VBmOqhZ4vJ+/k16IW83XV8NcroIrqyfVJFRxVTCpitj4kDecqd9XHRE2/Xf5bb\n"
+                + "-----END CERTIFICATE-----\n",
+                /**
+                 * Signature Algorithm: sha256WithRSAEncryption
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 5 07:20:59 2018 GMT
+                 * Not After : May 31 07:20:59 2038 GMT
+                 * Subject: CN = localhost
+                 * ASN1 OID: prime256v1
+                 * Public Key Algorithm: id-ecPublicKey
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIICwzCCAaugAwIBAgIUHY0HRPAMz4oLuNzl/b39FHi6AgwwDQYJKoZIhvcNAQEL\n"
+                + "BQAwDzENMAsGA1UEAwwEcm9vdDAeFw0xODA2MDUwNzIwNTlaFw0zODA1MzEwNzIw\n"
+                + "NTlaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEH\n"
+                + "A0IABF1zheAdyEUerLNUqXHw2WmXnMVJnKSMTeq+bk9WsZGBOZzJcEtyr1887JAR\n"
+                + "urn0uJ7J3YLUNlMuHaSWZ8hExGujgdwwgdkwCQYDVR0TBAIwADALBgNVHQ8EBAMC\n"
+                + "A/gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFMzV+8JMWSrdIJ+iZE9K\n"
+                + "4zn+roK6MEoGA1UdIwRDMEGAFPDIEFjuw5ywR29h/uhG9/swgiyNoROkETAPMQ0w\n"
+                + "CwYDVQQDDARyb290ghQMn5uWCv35717MfQKP81nVKR3wZDARBglghkgBhvhCAQEE\n"
+                + "BAMCBkAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmlj\n"
+                + "YXRlMA0GCSqGSIb3DQEBCwUAA4IBAQCvyScCVQVTG3d3yLcLT/q6G1I8N/4JrvzZ\n"
+                + "126BHoh8Oej4pbqn05SPdT4VH+J4UbTA8uHH9CLrAQv3WAU+P+tjXf61IRYNCm73\n"
+                + "A6K7ZvkpZpnvyT3ynMpG509OZbKxQrJWvyN22MTApi7Y8+s3+UAwUG4SZwlEHLn+\n"
+                + "sGASjfYouH4BRbymeNmuoHXWHO/P8O52cylElyUEHcwJx17IqJRNcwMb2aexPe+h\n"
+                + "P3HcVS6fxFW1I02cq62KEfexRTvVNijXU8vaYDC0aP0M+fMN/xc/HPJiUyRNCKOC\n"
+                + "Q8B6w2/GDQQeVbxoO0CLuHuOodA+oJIw4bX0y4XvTs76HK1R/nue\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVHQp1EG3PgASz7Nu\n"
+                + "uv9dvFLxsr3qfgC6CgZU4xorLbChRANCAARdc4XgHchFHqyzVKlx8Nlpl5zFSZyk\n"
+                + "jE3qvm5PVrGRgTmcyXBLcq9fPOyQEbq59Lieyd2C1DZTLh2klmfIRMRr"
+        ),
+        ecdsa_sha1(
+                "EC",
+                /**
+                 * Signature Algorithm: ecdsa-with-SHA1
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 4 15:20:45 2018 GMT
+                 * Not After : May 30 15:20:45 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: id-ecPublicKey
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIBdzCCAR+gAwIBAgIUO79CpzonO37fqCHN1VHS+aa5t5owCQYHKoZIzj0EATAU\n"
+                + "MRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTgwNjA0MTUyMDQ1WhcNMzgwNTMwMTUy\n"
+                + "MDQ1WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"
+                + "BwNCAAR6LMO6lBGdmpo87XTjtA2vsXvq1kd8ktaIGEdCrA8BKk0A30LW8SY5Be29\n"
+                + "ScYu8d+IjQ3X/fpblrVh/64pOgQzo1AwTjAdBgNVHQ4EFgQU3RhUvLzu/b6sNegl\n"
+                + "/5TPncFFh4MwHwYDVR0jBBgwFoAU3RhUvLzu/b6sNegl/5TPncFFh4MwDAYDVR0T\n"
+                + "BAUwAwEB/zAJBgcqhkjOPQQBA0cAMEQCIEle4IWFybL1xKVmFCNnR8bK1l5LzqAj\n"
+                + "YBdXK+LBJDliAiBFKkkOaZsXZir09t1tgPNneIgYMeXCQAJ1mQ7rQRiKPg==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgyJJNI8eqYVKcCshG\n"
+                + "t89mrRZ1jMeD8fAbgijAG7WfgtGhRANCAAR6LMO6lBGdmpo87XTjtA2vsXvq1kd8\n"
+                + "ktaIGEdCrA8BKk0A30LW8SY5Be29ScYu8d+IjQ3X/fpblrVh/64pOgQz"
+        ),
+        rsa_pss_pss_sha256(
+                "RSASSA-PSS",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 6 07:11:00 2018 GMT
+                 * Not After : Jun 1 07:11:00 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsassaPss
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDZjCCAh2gAwIBAgIUHxwPs3eAgJ057nJwiLgWZWeNqdgwPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC\n"
+                + "AgDeMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA2MDYwNzExMDBaFw0zODA2\n"
+                + "MDEwNzExMDBaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASAwCwYJKoZIhvcNAQEK\n"
+                + "A4IBDwAwggEKAoIBAQCl8r4Qrg27BYUO/1Va2Ix8QPGzN/lvzmKvP5Ff26ovNW4v\n"
+                + "RUx68HzAhhiWtcl+PwLSbJqJreEkTlle7PnRAypby3fO7ZAK0Y3YiHquaBg7d+7Y\n"
+                + "FhhHwv8gG0lZcyA0BkXFJHqdq76qar0xHC6DVezXm0K3mcceymGtFR9BzWmAj+7D\n"
+                + "YsSwvtTQ7WNoQmf0cdDMSM71IwaTwIwvT2wzX1vv5hcdDyXdr64WFqWSA9sNJ2K6\n"
+                + "arxaaU1klwKSgDokF6njafWQ4UxdR67d5W1MYoiioDs2Yy3utsMpO2OUzZVBZNdT\n"
+                + "gkr1jsJhIurpz/5K51lwJIRQBezEFSb+60AFVoMJAgMBAAGjUDBOMB0GA1UdDgQW\n"
+                + "BBQfFit5ilWJmZgCX4QY0HsaI9iIDDAfBgNVHSMEGDAWgBQfFit5ilWJmZgCX4QY\n"
+                + "0HsaI9iIDDAMBgNVHRMEBTADAQH/MD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUD\n"
+                + "BAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3gOCAQEAa4yUQ3gh\n"
+                + "d1YWPdEa1sv2hdkhtenw6m5yxbmaQl2+nIKSpk4RfpXC7K1EYwBF8TdfFbD8hGGh\n"
+                + "5n81BT0/dn1R9SRGCv7KTxx4lfQt31frlsw/tVciwyXQtcUZ6DqfnLP0/aRVLNgx\n"
+                + "zaP542JUHFYLTC3EGz2zUgv70ZUTlIsPG3/p8YO1iXdnYGQyzOuQPUBpI7nS7UtR\n"
+                + "Ug8VE9ACpBxxI3qChMahFZGHlXCCSjSmxpQa6UO4SQl8q5tPNnqdzWwvAW8qkCy4\n"
+                + "6barRQ4sMcGayhHh/uSTx7bcl0FMJpcI1ygbw7/Pc03zKtw0gMTBMns7q4yXjb/u\n"
+                + "ef47nW0t+LRAAg==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEuwIBADALBgkqhkiG9w0BAQoEggSnMIIEowIBAAKCAQEApfK+EK4NuwWFDv9V\n"
+                + "WtiMfEDxszf5b85irz+RX9uqLzVuL0VMevB8wIYYlrXJfj8C0myaia3hJE5ZXuz5\n"
+                + "0QMqW8t3zu2QCtGN2Ih6rmgYO3fu2BYYR8L/IBtJWXMgNAZFxSR6nau+qmq9MRwu\n"
+                + "g1Xs15tCt5nHHsphrRUfQc1pgI/uw2LEsL7U0O1jaEJn9HHQzEjO9SMGk8CML09s\n"
+                + "M19b7+YXHQ8l3a+uFhalkgPbDSdiumq8WmlNZJcCkoA6JBep42n1kOFMXUeu3eVt\n"
+                + "TGKIoqA7NmMt7rbDKTtjlM2VQWTXU4JK9Y7CYSLq6c/+SudZcCSEUAXsxBUm/utA\n"
+                + "BVaDCQIDAQABAoIBAAc4vRS0vlw5LUUtz2UYr2Ro3xvRf8Vh0eGWfpkRUiKjzJu6\n"
+                + "BE4FUSh/rWpBlvcrfs/xcfgz3OxbjIAZB/YUkS9Vd21F4VLXM7kMl2onlYZg/b/h\n"
+                + "lkTpM3kONu7xl6Er9LVTlRJveuinpHwSoeONRbVMSGb9BjFM1VtW4/lVGxZBG05D\n"
+                + "y9i/o4vCZqULn9cAumOwicKuCyTcS58XcMJ+puSPfRA71PYLxqFkASAoJsUwCXpo\n"
+                + "gs39lLsIFgrfO8mBO1ux/SE+QaRc+9XqFSHHKD1XqF/9zSYBgWjE910EcpdYEdZx\n"
+                + "GEkwea7Fn4brO5OpIrHY/45naqbUOBzv6gufMAECgYEAz7PHCdcrQvmOb8EiNbQH\n"
+                + "uvSimwObWJFeN1ykp6mfRbSnkXw7p8+M4Tc8HFi8QLpoq63Ev2AwoaQCQvHbFC2Y\n"
+                + "1Cz0EkC0aOp+tZP7U2AUBdkcDesZAJQTad0zV6KesyIUXdxZXDG8JJ1XSNWfTJV4\n"
+                + "QD+BjLZ0jiAyCIfVYvWQqYkCgYEAzIln1nKTixLMPr5CldSmR7ZarEtPJU+hHwVg\n"
+                + "dV/Lc6d2Yy9JgunOXRo4BXB1TEo8JFbK3HBQH6tS8li4qDr7WK5wyYfh8qb4WZyu\n"
+                + "lc562f2WVYntcN8/Ojb+Vyrt7lk9sq/8KoVHxEAWd6mqL9VTPYuAu1Vw9fTGIZfB\n"
+                + "lDeELYECgYAvdzU4UXzofGGJtohb332YwwlaBZP9xJLUcg6K5l+orWVSASMc8XiP\n"
+                + "i3DoRXsYC8GZ4kdBOPlEJ1gA9oaLcPQpIPDSLwlLpLM6Scw4vI822uvnXl/DWxOo\n"
+                + "sM1n7Jj59QLUhGPDhvYpI+/rjC4wcUQe4qR3hMbUKBVnD6u7RsU9iQKBgQCQ17VK\n"
+                + "7bSCRfuRaxaoGADww7gOTv5rQ6qr1xjpxb7D1hFGR9Rc+smCsPB/GZZXQjK44SWj\n"
+                + "WX3ED4Ubzaxmpe4cbNu+O5XMSmWQwB36RFBHUwdE5/nXdqDFzu/qNqJrqZLBmVKP\n"
+                + "ofaiiWffsaytVvotmT6+atElvAMbAua42V+nAQKBgHtIn3mYMHLriYGhQzpkFEA2\n"
+                + "8YcAMlKppueOMAKVy8nLu2r3MidmLAhMiKJQKG45I3Yg0/t/25tXLiOPJlwrOebh\n"
+                + "xQqUBI/JUOIpGAEnr48jhOXnCS+i+z294G5U/RgjXrlR4bCPvrtCmwzWwe0h79w2\n"
+                + "Q2hO5ZTW6UD9CVA85whf"
+        ),
+        rsa_pss_rsae_sha256(
+                "RSA",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 6 07:11:39 2018 GMT
+                 * Not After : Jun 1 07:11:39 2038 GMT
+                 * Subject: CN = root
+                 * Public Key Algorithm: rsassaPss
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDXDCCAhOgAwIBAgIUM883yXaRA3QIV+WMuFpPscABr3IwPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC\n"
+                + "AgDeMA8xDTALBgNVBAMMBHJvb3QwHhcNMTgwNjA2MDcxMTM5WhcNMzgwNjAxMDcx\n"
+                + "MTM5WjAPMQ0wCwYDVQQDDARyb290MIIBIDALBgkqhkiG9w0BAQoDggEPADCCAQoC\n"
+                + "ggEBAL5mCEWQRETgkJpn/RdyQZed7gXJEBrlsF0VcTs6RbEHx4clDnhiySPrqX2p\n"
+                + "KgfpMtxt6wKV+qY6+mSKyhDlUnVVgNdX0IgyXXXl5zcCfVRkbqEwRoon0HRLilaP\n"
+                + "NAeLhQDOtR4Kuw+tGaLMMUncdVoIlgR4TCEgWVkiX+Xri7/A2t8vnBgE8xxp+Xbl\n"
+                + "r/gYBS0K68zyGCSEQY0DltiPkWgvLWYiFAuDYobJZhVcDDNbgIMdzS9KfDX8Pm7F\n"
+                + "OC4Uu5Us4QemADFX/Iqf/jURJjJJ1lJpH9ue2I3tpJhVMg7lumfrc+Mf0+85St7Y\n"
+                + "smxURgAd2Qv9ecpMtk3ROYci2UkCAwEAAaNQME4wHQYDVR0OBBYEFINgLu8Yw9nh\n"
+                + "J5xEH0/w9NOVEOFNMB8GA1UdIwQYMBaAFINgLu8Yw9nhJ5xEH0/w9NOVEOFNMAwG\n"
+                + "A1UdEwQFMAMBAf8wPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgGhGjAYBgkq\n"
+                + "hkiG9w0BAQgwCwYJYIZIAWUDBAIBogQCAgDeA4IBAQBjuUjrtllwaE1ZB7+nCiDT\n"
+                + "0o4SoX+1klU0M45L/IBsqIJI0uyBdwToPFXaswK0JrC3YuoOGjBfWlDGtmcoG0L8\n"
+                + "V3nlWh0QO2/XQYjpT8SMRLcP9xRpY/rap85LqTkPlGhk3h0Z0LZTuK9KGznaHB/X\n"
+                + "RfIRAerYwkRV6F4YbpJxLkZ/1udutQcByKXnGaosFZSZVyfy/Xn0+xWiBkuGv6hC\n"
+                + "pZh0//f+9cjUiWChx0ROa+3DmDc5mzFIxC0VGMGZWSekgFAyi7eOu09DB2BDg2O/\n"
+                + "C3MPBzynuw9E1a4NhEqNx+Cm0gJj5ZAUAAE1/aR8103fND3CA1SqiTgDVJh9Xg8i\n"
+                + "-----END CERTIFICATE-----\n",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 6 07:11:39 2018 GMT
+                 * Not After : Jun 1 07:11:39 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIID8DCCAqegAwIBAgIUC+I1WgIEDAn5GlIUequsVbhnSr4wPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC\n"
+                + "AgDeMA8xDTALBgNVBAMMBHJvb3QwHhcNMTgwNjA2MDcxMTM5WhcNMzgwNjAxMDcx\n"
+                + "MTM5WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n"
+                + "DwAwggEKAoIBAQDD8nVjgSWSwVmP6wHXl+8cjESonTvCqSU1xLiySoqOH+/u5kTc\n"
+                + "g5uk7J9qr3sDpLLVmnB7lITrv3cxX7GufAC2lrWPhKdY2/BTpCGP4Twg/sC7Z2Mn\n"
+                + "APNabmPh+BhpQA3PllULdnsV/aEKeP3dFF+piJmSDKwowLhDc0wdD1t15jDk812U\n"
+                + "nNQugd465g0g6z57m3MFX1veUryaNqgoHncuVRjvXPm2HHKUYvIt28Od3w+LbOGe\n"
+                + "U2ykiS/KC0QQMsW7JZzeFSoogkZry/rUz1MJVSA49QNSVOdmVuUvD9tX8q+Dv+lD\n"
+                + "G20+9c6sz9qbzlJk4uOx39ES98Y5vAVA25C/AgMBAAGjgdwwgdkwCQYDVR0TBAIw\n"
+                + "ADALBgNVHQ8EBAMCA/gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFHju\n"
+                + "i01kwWAQXy8XCa7MFigVAz/pMEoGA1UdIwRDMEGAFINgLu8Yw9nhJ5xEH0/w9NOV\n"
+                + "EOFNoROkETAPMQ0wCwYDVQQDDARyb290ghQzzzfJdpEDdAhX5Yy4Wk+xwAGvcjAR\n"
+                + "BglghkgBhvhCAQEEBAMCBkAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJh\n"
+                + "dGVkIENlcnRpZmljYXRlMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUDBAIBoRow\n"
+                + "GAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3gOCAQEAsasJTqce1nlDSl+L\n"
+                + "rHuKiuQhr2KFq9DIXrTe2TEPIKBIEQnMOX/fHtahOAvkdgQmv573Z63uzHWoWSie\n"
+                + "V5+fHDOOL0vGQ1y3hklIqPnNs0cOORr0sed2p5ibwM1W3OBHRGqWtdYHf0o3sJnD\n"
+                + "vHo1Vhxc6Zabv5Bf1pTT3GGL4cM66LRWJAoDOx4RiCZObBqDUhZ7z9ntJM+o8xtE\n"
+                + "4uf08tqOESQ1hJSug9GApSX5QKu59BkPza4KTCjz6tagBKBF7x/CUbYcbjsWe8A6\n"
+                + "TZAyfBFsdj3G20BL+o3+zCy6yBUB6Z/DzB1zx65roVt9BpF0reHHCA2/gwa9sKYh\n"
+                + "qx2Knw==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDD8nVjgSWSwVmP\n"
+                + "6wHXl+8cjESonTvCqSU1xLiySoqOH+/u5kTcg5uk7J9qr3sDpLLVmnB7lITrv3cx\n"
+                + "X7GufAC2lrWPhKdY2/BTpCGP4Twg/sC7Z2MnAPNabmPh+BhpQA3PllULdnsV/aEK\n"
+                + "eP3dFF+piJmSDKwowLhDc0wdD1t15jDk812UnNQugd465g0g6z57m3MFX1veUrya\n"
+                + "NqgoHncuVRjvXPm2HHKUYvIt28Od3w+LbOGeU2ykiS/KC0QQMsW7JZzeFSoogkZr\n"
+                + "y/rUz1MJVSA49QNSVOdmVuUvD9tX8q+Dv+lDG20+9c6sz9qbzlJk4uOx39ES98Y5\n"
+                + "vAVA25C/AgMBAAECggEAD8rgzy4/ev5+W20Tbu7d5K0hc32IrX24dAbw493CIQZN\n"
+                + "7jE855Dr4HT5vD18aqTBjRmvayZjOCTsVFxkE64G2LB43aJRYoYHbpZR5ii/EeG2\n"
+                + "YuRIR4J6GpW/Ex1Nyl3RPyPcotnfvbv9WLy7qS/VLfLGfdDrpzUxJK6MOeNc+bl5\n"
+                + "qB1ulSCaFAM9shaEKW1jXHoHhl386dtduXtCOZNU2OTmSAqh5GHKTN0CuNF9b2Ys\n"
+                + "3gkwVdxwle3EaY97mJVqoB3YCBZgRnT3oilJCRM7L4y6W4MVL0AmDlBrPtvsxRIS\n"
+                + "obFPm6c0qLVoPVbw2Z2PO9XLJmsrEAsFoVxYe8lAgQKBgQDjQ3R61ksPrmq1TDl5\n"
+                + "wK5FlfUfAmnnt0Sh1Sk8xSkAcEaRyTil0vKYM/flsHVD949rJm15uJ4jhKQd8+f+\n"
+                + "GQDj//yCNi3b/JRcOZJ4zMSnB6u4r+YJ7C5CwiGPmAm668SCvoskq93yCZ3RixM6\n"
+                + "59Tj7V7GQo+9gazkt1hGEcR0nwKBgQDcuUnUXshzubOftS6+nFvCO8F4JfmoHbxp\n"
+                + "DO3VZAvuimdbxjscMtuYVWa097gzatApkfjL4ZlxuL2yxx5GDy9mW6ipJpM/NBvC\n"
+                + "fvN23dzoKf1zJ9yh2jZIb4z7q87LwHiiQ7TZrOno8M8Szv7qs8K4W+/0IY6fk7Yz\n"
+                + "l9AgHExP4QKBgQCyE9Q8wJf2hKwWvdC3p5Sm8BcvojuMFx4PVTFH7hHvxwp1B+B8\n"
+                + "h2wSeX5BG+D3Tg+yXV0hKNm5aSEUW1+oyrzY62hYO835d9Rk47PzNjjNzQPw5tvx\n"
+                + "YIDrTKTxmKffMQk9jcMIDCgQlRp17G04FhrKMuC1p8hsLSVl3oir9xYibwKBgEHz\n"
+                + "Yyn/gCmD7TXlLyhpE8m/jRlXT3d6GxfQcyf1ktMdq7ByVKsiTxb/PYcJFZLXcYda\n"
+                + "RFq29+BQ8O2ALX2FgAY3kPepvQl/imPdBuYXeLAuC7riyDvcNagDHL7+IPYkdmcV\n"
+                + "j+4Sinm9qkHWc7ixKZdocRQjCriHrENSMy/FBNBBAoGAfi0ZGZxyIeik5qUBy+P+\n"
+                + "+ce6n5/1kdczPTpzJae+eCPqg3VQuGz3NutZ2tdx1IMcYSeMfiB6xLMWSKSraxEi\n"
+                + "2BCtdPcyUau8w12BXwn+hyK2u79OhHbexisrJUOVXE+yA8C/k0r0SrZHS0PHYZjj\n"
+                + "xkWyr/6XyeGP/vX8WvfF2eM="
+        ),
+        rsa_pkcs1_sha1(
+                "RSA",
+                /**
+                 * Signature Algorithm: sha1WithRSAEncryption
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 4 15:23:09 2018 GMT
+                 * Not After : May 30 15:23:09 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDBjCCAe6gAwIBAgIUYYGwpeC0sJpk4SP0SYgAiN9Z1qswDQYJKoZIhvcNAQEF\n"
+                + "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNDE1MjMwOVoXDTM4MDUz\n"
+                + "MDE1MjMwOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
+                + "AAOCAQ8AMIIBCgKCAQEApbeNHuHv5VuUteMxa5Ga4N2QDnmGk1pAGuhFVG7Roh/3\n"
+                + "kU3gJzg0UHsvc0BUWPHDOoswYXiW3zzfa2TdUny/EeF3xxw10vbnV+M1iDnKwDEM\n"
+                + "aCtihBTHCdRd3DBRkNbyDPgOBU4zmx5fZhLej6tC0Ez5V+yScPtUe0RCWEpMRZu4\n"
+                + "f5bK//AknFcReEmbTuvxDD6BtpEj8pUJatWIuPPgQRbjzm37WL9ZsnwldLNAvPdx\n"
+                + "DBNfmGhOrIwJJ6m/ihlJgiwoM4Ffpqa/I+gciDUX9xPogFi9f93ShL9FyGDQO28+\n"
+                + "0HOgDi9O3KthJ17QCSOkG3leIWm/bqE4wQ3iMF3EzQIDAQABo1AwTjAdBgNVHQ4E\n"
+                + "FgQU1t/aKj/JelP2U02UaK4ICGLigtwwHwYDVR0jBBgwFoAU1t/aKj/JelP2U02U\n"
+                + "aK4ICGLigtwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAnVX/n4/A\n"
+                + "0KMrjkbXYGSjECTXy15xIrMME71eD4HvCe3n5E5ONBfivPGsj9z+y73pQJm92F1v\n"
+                + "Wi2Y1+819ObYwXTrI1b0zgV8WJ6pj+E14eNECM5npEH/QJMSVeJLWCuisQGTaGJH\n"
+                + "TTemZfOTspmFQ9V/meOXjh7kgmF5plclnhDgwLe5Ryih665YOADxxgncP6ViQibI\n"
+                + "dSTnGH4+Ikj6iQja/Xxb1uc7KYMqQsji7oUHp/NDwM6av1tbdt5TMSrwnT1T36D+\n"
+                + "zc/Kua1BkI3RqfooZ1CIQc0lHr8Au7fG/HNDPBNPFuB/g0c7IE4l0bcjEIDJEtj+\n"
+                + "dmEitVZ8mcuRgQ==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQClt40e4e/lW5S1\n"
+                + "4zFrkZrg3ZAOeYaTWkAa6EVUbtGiH/eRTeAnODRQey9zQFRY8cM6izBheJbfPN9r\n"
+                + "ZN1SfL8R4XfHHDXS9udX4zWIOcrAMQxoK2KEFMcJ1F3cMFGQ1vIM+A4FTjObHl9m\n"
+                + "Et6Pq0LQTPlX7JJw+1R7REJYSkxFm7h/lsr/8CScVxF4SZtO6/EMPoG2kSPylQlq\n"
+                + "1Yi48+BBFuPObftYv1myfCV0s0C893EME1+YaE6sjAknqb+KGUmCLCgzgV+mpr8j\n"
+                + "6ByINRf3E+iAWL1/3dKEv0XIYNA7bz7Qc6AOL07cq2EnXtAJI6QbeV4hab9uoTjB\n"
+                + "DeIwXcTNAgMBAAECggEAWiZUOuymWJtNdvU1OVNocdOWPomV0CtUnE6nCJuQpyXE\n"
+                + "w+MdgbhtnSqmUYg5WnmKvxphI2U6jg7La9zfGbSLLOr/Ae4yyaVPjNwpjwYBajRE\n"
+                + "j5aqbTfwX0SMGvCeLrD/1FZNKk20fTo0o464TGfaXP7C1jX4JEZVWwlzHhytCWAg\n"
+                + "tkApQmmU0AsDnLll4zWDa/IeeVDJXkF95S4Dyj0LCrJ8+9PF2zN0AKYGuDjOWY2d\n"
+                + "yeWW9oXI7zzBBtCriPy+GYXNpHmfpURCWBt4Nc89EV2qB6ZYmMXkspfA/wLtcRm1\n"
+                + "zchbptCakgaNfw5qMJrucB5Jz1I7vfMSlcu4VZ0lAQKBgQDZ5PvqVet5/flPaJTR\n"
+                + "Ct8Ye1Y62lZgz1woNjzhC0btL2eAcMtgsebznlTFY4NLb4M2eo7CabSGs7xykhBS\n"
+                + "t4o//eh+MupMYHYGrzaPHjRnBbm/mTR1DUuPmBX6ZGtwXifFmwvhZdaRWuCzVoYN\n"
+                + "uUONvUV5R/xz9niyXRtN1HVLMQKBgQDCspxCgHc3OvXYEHl10Yoc4qsGH+7NQTAA\n"
+                + "5TzhhdxcR6vxnBJSKh/kzMPM4QYXdwPfaHMsay+FEiGz6agdKgtTAA6mKnjjM4zk\n"
+                + "e/J9ou8QWm08T0GxUXcx1NGYM8Nsamz2svZ0XAe76I0hhosV5nxmXabayPgHe50L\n"
+                + "8SD6qFO0XQKBgHO0bbVNNMLOA8KQJV4wKLHGZM7RvEaiNizASGm0ZFB0+MAypTzO\n"
+                + "m3ZIYHmE02aOa53VTNOd8BgLf4lTWMmj3w0GFpxVCyfNnT8FcbJj9q2yU6WThFCX\n"
+                + "48T3nMwe4RKFXRdIsvFY86yyFloFGyBUfbPZivfRKxSlEAie+m3E4RgxAoGAVrxT\n"
+                + "OJ0afxRZKWRNd9tdd/jSz+ux6ua7h+qX8LA9ty6GvyAUWV5Czx8Zq1Aj8pgmtYRG\n"
+                + "quclSFcHhKr3JebxHIzN+eC58h2pCrDdGnNXpSVjvJZiYag1PZHdvbxxtv7ChDS9\n"
+                + "7qCBIYk8Nk9F7v+7M69NAfK97Dd5gzRsyL3sbFECgYBxz2nCKeBv2frxtD36nlY1\n"
+                + "bDhZv1Asyxq0yt9GSkVWeHnSIFHfwBu3w6qW7+qdlQizu+6GZ3wq9dyyrXUA4zPU\n"
+                + "QnYWYYk30p4uqLXFCrnscVOm3v7f51oEYVoEKjqGl2C/BTy7iSgCRd+cp6y34DsV\n"
+                + "PsRyQCB/QarxsDNAuioguQ=="
+        ),
+        rsa_pkcs1_sha256(
+                "RSA",
+                /**
+                 * Signature Algorithm: sha256WithRSAEncryption
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 4 15:22:04 2018 GMT
+                 * Not After: May 30 15:22:04 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDBjCCAe6gAwIBAgIUc8yTYekR2LuXkkCJYqWlS/pBMKIwDQYJKoZIhvcNAQEL\n"
+                + "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNDE1MjIwNFoXDTM4MDUz\n"
+                + "MDE1MjIwNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
+                + "AAOCAQ8AMIIBCgKCAQEA2jDPGMogc9dq2w5b+FHqbfaGPokRmyObiU8y/l/dqkM5\n"
+                + "9IV+qj8VQUI4NtpdCTWr16812z4AjXrk5HIBrECfQbHPUcm1rme5YVZ0WxV0+Ufy\n"
+                + "hDmrGwDLhkxGqc3hOhRrlF2wdXeUfjIzhvS9+S/401++t/jvq+cqFF1BHnzYOu+l\n"
+                + "nbi/o95Oqo8MlwiRqg3xy3fNRfqXk7DWy+QT8s+Vc3Pcj1EW6K0iJJ23BVTdv6YT\n"
+                + "Ja5IKiWL4XsLht3fWvZwF+PoYfKb+JYflt0rafpxg9xkowe7GnGh2SpV7bJaH/QN\n"
+                + "3PTFEKQWgWHjWwjR171GOzSaEgaklvKde6+zNWeYKwIDAQABo1AwTjAdBgNVHQ4E\n"
+                + "FgQUqCtGe8/Ky4O6pH7xeTUy9yrv4n0wHwYDVR0jBBgwFoAUqCtGe8/Ky4O6pH7x\n"
+                + "eTUy9yrv4n0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAuqch30im\n"
+                + "M09sARarbfK3OExqYK2xoyuUscgTqQNDpNL2gMdXY9e0lTmGVgw9pVYtNZPZRxem\n"
+                + "jR5an2XegvG9qVU6vLENDwLCqZgsTb2gvmXngiG8NVcYd81GNqD228mkgBosNJku\n"
+                + "6BR+C8zlURzsNEt657eVvIp9ObGomdAbWhpdqihBD180PP18DIBWopyfHfJtT5FA\n"
+                + "U2kSPBp+P1EtdceW0zfwv3rF8hwRbnQBzuoYrZfn2PiMYaGUqOgbqUltCMD/Dp9G\n"
+                + "xK0nfAXEwIqHWWnijGwAd6YrszMjBUcSGmlehdF+XZK6jHNlw64RB4WTfavr+rY0\n"
+                + "dTe6g4o5GYr9nQ==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDaMM8YyiBz12rb\n"
+                + "Dlv4Uept9oY+iRGbI5uJTzL+X92qQzn0hX6qPxVBQjg22l0JNavXrzXbPgCNeuTk\n"
+                + "cgGsQJ9Bsc9RybWuZ7lhVnRbFXT5R/KEOasbAMuGTEapzeE6FGuUXbB1d5R+MjOG\n"
+                + "9L35L/jTX763+O+r5yoUXUEefNg676WduL+j3k6qjwyXCJGqDfHLd81F+peTsNbL\n"
+                + "5BPyz5Vzc9yPURborSIknbcFVN2/phMlrkgqJYvhewuG3d9a9nAX4+hh8pv4lh+W\n"
+                + "3Stp+nGD3GSjB7sacaHZKlXtslof9A3c9MUQpBaBYeNbCNHXvUY7NJoSBqSW8p17\n"
+                + "r7M1Z5grAgMBAAECggEAHs/7vw10TcejEHJTrJqs14CT7qresKDzqw1jLycMn6nE\n"
+                + "unJLs/EaqE+Yrq5hqxZIQTo+CcsUuuYbAuPStqedleJtW6h3nryJImTaI67BCR8O\n"
+                + "8XtPXY3cMAf/hqVLZC9UDey5Ka2Ma9HdEvbnCRSsN/VycnqWJhmMCLouowaQZqoE\n"
+                + "VopscUix8GqELv0vEo2CszZfUjtSVbNTlNgwDf5U7eSKXMuFsnSn/LE7AMvHsEyo\n"
+                + "HatxogwlM/WjpTnf/WIeJY3VhaK10IsP6OEgUn/p4VtI2DQ/TJdgYrvD5vhjY8ip\n"
+                + "XuUPuPILRvJWo8dRXJqa4diXB12q5YhP8iiOp4BgkQKBgQD1GtlOR+JVgOzpQ11h\n"
+                + "s5/iJOsczee80pQscbSRJnzSsIaP9WM8CyJgvbPxIQxLUQeYnxM/bxNKkpJtzxRK\n"
+                + "pob+v4NoRn8PTpqbOp1obmWJT7uHTaoeavQo7r7uZI4i3eEgHCCQkMzpqzz7UFTY\n"
+                + "2Yst7bBTPUivlSVQQBEc8bLpeQKBgQDj47EjpAlh8DmJRTElg58t+XJehXGTqmlx\n"
+                + "nYu8DQLSzGbOQ/Z4srakC1mkM0LHCmULIIWk3KhV1GBCeArv7DlZ9A1SkI95bsq9\n"
+                + "GBeQpovL0PXKkOOWMJBklP/CTECO4eyA8r6c1d8wytBb6MrJ8bi74DdT+JlFjK5A\n"
+                + "zNoeNx6JwwKBgQCehIPABeuSYvRVlDTDqFkh98B6+4wBaatc5xjhuyOFW5dbaVeJ\n"
+                + "kKXmLSpAK6B44WnpQhA/uUWfuBWtoPy9nt+1yARjnxwzuSFyfUEqNiPC32coBYmd\n"
+                + "bIyGIIopQa1PTXJ4wtgoxw1PnmitHHITYPaLeKrN2te0fuAH+7dVodeU+QKBgAct\n"
+                + "VJbaw7Dh7+3yz+lui8TW5lMzwK/13fxGCfCSOFSLO3Gjkk+a0UW5VclmE+RQ333K\n"
+                + "OGtIx8RsO9vcC/wiZGwA06qWAu7AHoJ2D8fudtikbBlFFuXUAbgpOSTVYfMeCmTF\n"
+                + "QFuQIMdYm9dJLZnOkxLXrOZoHeui0poX2Ya6FawhAoGAAI/QCyDbuvnJzGmjSbvl\n"
+                + "5Ndr9lNAansCXaUzXuVLp6dD6PnB8HVCE8tdETZrcXseyTBeltaxAhj+tCybJvDO\n"
+                + "sV8UmPR0w9ibExmUIVGX5BpoRlB/KWxEG3ar/wJbUZVZ2oSdIAZvCvdbN956SLDg\n"
+                + "Pg5M5wrRqs71s2EiIJd0HrU="
+        ),
+        rsa_pkcs1_sha384(
+                "RSA",
+                /**
+                 * Signature Algorithm: sha384WithRSAEncryption
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 7 07:59:56 2018 GMT
+                 * Not After: Jun 2 07:59:56 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDBjCCAe6gAwIBAgIUcjBWKuODVu3MEVfJLsTPV7yRdo8wDQYJKoZIhvcNAQEM\n"
+                + "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNzA3NTk1NloXDTM4MDYw\n"
+                + "MjA3NTk1NlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
+                + "AAOCAQ8AMIIBCgKCAQEAvIgnQr3nGpMz/QYksk2r+SpqbRhiOFno6c/kyJmSu8TQ\n"
+                + "08RV8Ad8CalnADkHlPBoTmCqY5v9aOupcl1+jCe7e4idz4IJsuY1KRU/Uj4lYVqO\n"
+                + "1W78HxIgKd3jbSgA9628lJ6Nhv6OqyA8KCInKboI8FdDmdRVzu+FCmGKLBtUVnOP\n"
+                + "OkzMzttkrg7oyUoCagYizZLY8lhUA8RfgxIMK3zhS1t3k5LbH36+kd6sECNrg5+y\n"
+                + "6Dbd7g67ja40ALZpWU75yLNR9G71XZ0b6HyFjbF31oVCHtoeN6MiEXYS0F6+VT+x\n"
+                + "y5xg4y4JZfZFJB7GUaAso4XZxKYTypv7DgPE7WquHwIDAQABo1AwTjAdBgNVHQ4E\n"
+                + "FgQUMQoCUE5YPhS4im6eAZaCRrNfqH8wHwYDVR0jBBgwFoAUMQoCUE5YPhS4im6e\n"
+                + "AZaCRrNfqH8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQwFAAOCAQEAm5o/OH/x\n"
+                + "i1Z4TVPYRDbDgRZoGsikQtt6JxYRgqhwHrTo188kJw61X4hRaMcV5Td8WTsqXJCq\n"
+                + "dfGGpV4L6FCwBNNNxIyHGTrtjNtGae2x2c9XYX0O6nnmgQP4+Koo7ouqpxmMzfGa\n"
+                + "uN3PWP8ABhEiLCBfRRK8w9kpxOuJfQyiwXQQN9TH6MU63O52ydA5NYA2RMbRcjsC\n"
+                + "BE4VHGsJJo1z8Z9KI7pdSvP3/wTSMVpYY6kxanMSHNeFV5aDfSOX8U8oqIF7xkiA\n"
+                + "o1CjhPYUvS9MEmoq74ulKNgfstjYcymiP10odaiv4wg1oIhxVtNV/fpdKQKHDeu0\n"
+                + "30Ac3llO11/faA==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC8iCdCvecakzP9\n"
+                + "BiSyTav5KmptGGI4Wejpz+TImZK7xNDTxFXwB3wJqWcAOQeU8GhOYKpjm/1o66ly\n"
+                + "XX6MJ7t7iJ3Pggmy5jUpFT9SPiVhWo7VbvwfEiAp3eNtKAD3rbyUno2G/o6rIDwo\n"
+                + "IicpugjwV0OZ1FXO74UKYYosG1RWc486TMzO22SuDujJSgJqBiLNktjyWFQDxF+D\n"
+                + "EgwrfOFLW3eTktsffr6R3qwQI2uDn7LoNt3uDruNrjQAtmlZTvnIs1H0bvVdnRvo\n"
+                + "fIWNsXfWhUIe2h43oyIRdhLQXr5VP7HLnGDjLgll9kUkHsZRoCyjhdnEphPKm/sO\n"
+                + "A8Ttaq4fAgMBAAECggEBAJp+lHW7+wsq/9pj02SOA9RubsIxziNRgm0/4MKGHtli\n"
+                + "QqKW7LmC2KFuQarMESt7Cm7YBikUZkg5fiTq+s3NrXRhErk+XcZNodilwbsalDVA\n"
+                + "KXY7ub2Yc+T7IOiNdKWCqNu9RksOhUk0ZDebLS6jdbnGOO5xM1QdsY89OSZFywn/\n"
+                + "xk1S+gvx5f7icchhSvPse3H2Sw3411HriWB83cDH09YPCZcJTv2QM/xophSru2j/\n"
+                + "kpRQhnJqGZ1M+1QDVi5HWNx+Y5v0QuCVWOi8Hat/S7x2J3opAqaCIjK0ErOC/OdY\n"
+                + "BJqjOyH8tfwnkwD+ghGIj44/lDsi0GY/2CsD63PNX7kCgYEA5Nz5pIi//2FqnOS7\n"
+                + "Pnvo374ZhMaepwvDdGOfkDDyL6k+5pLaO4SL5znQQzGmM6EWi3z7ZKw99MzQcwR6\n"
+                + "4COAgBqDm0vXY0MI4vLPzZpOe6hABieiaj4tvG9Ts2yqjBPLo6mZ6UDMFbg4Tt0F\n"
+                + "bfaqF5jA/mR2SpBzhRIeX0/eW3sCgYEA0uLw75774f6hnUWqi2jMtgwiOHXSFb+f\n"
+                + "bnxWGNJfxVW76rVh9892m1FXdU8SZivwg50dvo/GDQ1NsaaL5ypPsoP4d00336VT\n"
+                + "Gx1NAlo9WuD306cYXzMUmXCCwoCbOw7vdAAoIEDei8+nr6QO7yb5/FsWrmSZuadf\n"
+                + "ljLT+02f1K0CgYEAq0j7CfpS//ZPzXae8OfZ5UKoZKgma00xjnVVIZyQVb1sVzMH\n"
+                + "Y84Syw6I4RFSm4dvkRwMJk+G2yVCySJMOF45uSae4uaDIEY2a2xgvDdFj+TfbfvR\n"
+                + "4YQBxOrpEPs+NTJHkYjIqTsWwxaqBdQDUUZwDNMFdh+ILMwpuSlTU/A5sesCgYEA\n"
+                + "q+Y7OUfhz/TMbjN0chDqFVbMqjM4HWxGnDwTvkX1tRhOhmJ1yhc9ehuS69eZitk0\n"
+                + "Q0RWE5iEeu0mMLIuhi8SKdSzOyQhcFcF6Cs5M7q1GpgYy1kAX9F2cCCrJbrJThm9\n"
+                + "jFP4YVofTd3ltSFI3x5pVZA2a88rE49gNkGWU9mReD0CgYEAkXoH6Sn+Elp6Oa+k\n"
+                + "jF5jQ14RNH4SoBSFR8mY6jOIGzINTWiMCaBMiPusjkrq7SfgIM3iEeJWmgghlZdl\n"
+                + "0ynmwThnfQnEEtsvpSMteI11eVrZrMGVZOhgALxf4zcmQCpPVQicNQLkocuAZSAo\n"
+                + "mzO1FvNUBCMZb/5PQdiFw3pMEyQ="
+        ),
+        rsa_pkcs1_sha512(
+                "RSA",
+                /**
+                 * Signature Algorithm: sha512WithRSAEncryption
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 7 08:00:45 2018 GMT
+                 * Not After: Jun 2 08:00:45 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDBjCCAe6gAwIBAgIUZEjv/5m6CpjS/ZAZ20O81p64tCwwDQYJKoZIhvcNAQEN\n"
+                + "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNzA4MDA0NVoXDTM4MDYw\n"
+                + "MjA4MDA0NVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
+                + "AAOCAQ8AMIIBCgKCAQEA2heH4cASjGrc2ir6n4pqoQSzT5mhlR8/iF/5XrfISSbn\n"
+                + "fZNZnPk2cTQSDD8HNbRT9bvtrIYQITrGgUYKBTwtwycsM6v76+TFWsPBHWbn8bny\n"
+                + "eGsFxhNXsrRXZYiqDwoiPE+J8aTQMt4WlNBaZjt/9BEUYyTyZ8c53WWaE9aSE3sQ\n"
+                + "ynulZ8ruhkc9hbybEO1UfAQEWIY+nR0U9aBPSkmMxGbYaVhRecI6U5f2HpUA1llx\n"
+                + "LXJRD7PpiljccbxH2sNUdB4zL72XLsY1hn7igb0V9nNy79dzBTplmygEFv3ciLNi\n"
+                + "Jx5kOWEtuQh/DlWxptIW85lHugjkNdDnyiinCjIUBQIDAQABo1AwTjAdBgNVHQ4E\n"
+                + "FgQU8u4DRt2RBndU7GqGw9/IFdkfMRwwHwYDVR0jBBgwFoAU8u4DRt2RBndU7GqG\n"
+                + "w9/IFdkfMRwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQ0FAAOCAQEAWt8hlw9e\n"
+                + "kCFqGd+MqZLGg6Lv5tgJ1GRb+tMmGfRTwG0kegBzY7qU4ZZvasRH0F0lT7G8YNGs\n"
+                + "Asddvx6WuCQxW+V9WAfZMorSyUE1PKm0OR/vyZoZ7KoqWfMuxsPG6C/uh5Np4gd8\n"
+                + "8dIAASemQo8zLI+MBUjOiww+EwXkZ14m8vKAxKDk9JxzmgrkgH3U6CxhFgm51bmx\n"
+                + "d6axFU4srW+wjONb4nWLh3Cd9cSwL9nvbIG09T9xDf783uz3NYIqsmrKSP4h76WQ\n"
+                + "dueGgIRtJkV/x2dOmbCAh+SbY99kWG2wVFDmznweYSqzaqNfX4uiIkFB8M1Pi/9W\n"
+                + "ZOZBzpaxm+ARCw==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDaF4fhwBKMatza\n"
+                + "KvqfimqhBLNPmaGVHz+IX/let8hJJud9k1mc+TZxNBIMPwc1tFP1u+2shhAhOsaB\n"
+                + "RgoFPC3DJywzq/vr5MVaw8EdZufxufJ4awXGE1eytFdliKoPCiI8T4nxpNAy3haU\n"
+                + "0FpmO3/0ERRjJPJnxzndZZoT1pITexDKe6Vnyu6GRz2FvJsQ7VR8BARYhj6dHRT1\n"
+                + "oE9KSYzEZthpWFF5wjpTl/YelQDWWXEtclEPs+mKWNxxvEfaw1R0HjMvvZcuxjWG\n"
+                + "fuKBvRX2c3Lv13MFOmWbKAQW/dyIs2InHmQ5YS25CH8OVbGm0hbzmUe6COQ10OfK\n"
+                + "KKcKMhQFAgMBAAECggEAFE5YkoZls7lHcvDJgQ1MPE3JvEGbr9zG95WoDE+kUFtU\n"
+                + "9nY/w8PYc9XbUFSWAUQXBSxIRuX8nntwfBzfVflycVc2YGFFBYO5dGgBlRE9y136\n"
+                + "24drdDPc2IC+GnANFXVmFqN5PoyP7gyLobN8l0Q296yXb1vDTjJYiuqo2+wAkduZ\n"
+                + "gQDjl1jTS/1RXjix7Kaw9PrO5ONqp9f8FqJCVyezhp+OMNA88Uz619jvYC4axNh4\n"
+                + "zjESAf1YXPJUTM9nznmFQ8jS4+6I0yvf0jaNpCY1bC7kaHBMKkYWiBMPaNWYHa9o\n"
+                + "9EyPN5tPk8OTk/m9+e98vo9R1JR9016TKxDQtRxzAQKBgQDztIFeYuAUh5uTAGe+\n"
+                + "7FTfnsF+Pl3raWUf9T8d/m+3XujAXNrtURb2TkyQlsB+cNWa9VH/mMGz5RFE1mlC\n"
+                + "XaWKPrf0SAdbmx+wcRrEOlf+ARNj8XbEyKptpi7tgN11s6Eyztkn6xwUmSCEuZ+x\n"
+                + "Rly2F6A3FuHTJh24yjIFnP8vZQKBgQDlGDoFj9mKKkbAxoZGZYN/B+T5EUAW/OaH\n"
+                + "Oaxqi55QpGCbxGVR+G0AMG6WEN81qm812GTHJD22As6Lz9zFThKkJN2za43CAgrq\n"
+                + "MA7KgqO0w5rvuXXiPCHZUvdDkKFpIMZj4ftq83Xh3mkN5mbhF9FP0v3/xrczowYP\n"
+                + "oj11IHWYIQKBgQDkuvfo5Jg37IcB05GLyjhmoZQtrs9rkcIN2ppgxluIGZYOZZg8\n"
+                + "wKzyg86srjEA+1ogVDufz3mOJGKu3yZv2YDzXaY9qhTtz4xQh/d9UN0hU1Ulqo20\n"
+                + "aDo9K4pD83znaa7UBvwd0TbLxmSU7buKIOYHKel/iwRsrwuaUnvcdNu1WQKBgBa0\n"
+                + "SvPIKNgPjomGY0JQxzJstt2UPxTIJZSbO6Inih4V3FkzopL4Gt1c72jB7U0lQfZF\n"
+                + "Jt+xkMgcCRpEFG4daa2I1cv1ScxDZY+GCcE6Jz0/8Xf2ml88dGJUXZr9l3GSxPab\n"
+                + "K86SqEklQKYXAnUmZiESGQgjSn68llowSwTznZPhAoGBAMH2scnvGRbPmzm91pyY\n"
+                + "1loeejtO8qWQsRFaSZyqtlW1c/zHaotTU1XhmVxnliv/HCb3t7qlssb3snCTUY9R\n"
+                + "mcyMWbaTIBMNfW2IspX4hhkLuCwzhskl/08/8GJwkOEAo3q/TYigyFPVEwq8R9uq\n"
+                + "l0uEakWMhPrvr/N1FT1KXo6S"
+        ),
+        ecdsa_secp384r1_sha384(
+                "EC",
+                /**
+                 * Signature Algorithm: ecdsa-with-SHA384
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 7 08:02:00 2018 GMT
+                 * Not After : Jun 2 08:02:00 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: id-ecPublicKey
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIBuDCCAT2gAwIBAgIUIs1pMDA3bRg9B2OP7GFMAYxhr8owCgYIKoZIzj0EAwMw\n"
+                + "FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNzA4MDIwMFoXDTM4MDYwMjA4\n"
+                + "MDIwMFowFDESMBAGA1UEAwwJbG9jYWxob3N0MHYwEAYHKoZIzj0CAQYFK4EEACID\n"
+                + "YgAEeXrId3yy/0mJPNXXGXlMSQEvIpSyDCcKKQd2Zm1qt0gA1HUSHulfStyHUI6D\n"
+                + "l/pY7iR0wO/xYIWhirmqT+XbVPTWIJb245Lf9GFiR/d6UyUbqXuNg9GpnURsy5Zh\n"
+                + "x4Dfo1AwTjAdBgNVHQ4EFgQUk3NPE5K8ovMPNFtzX27rprTndU0wHwYDVR0jBBgw\n"
+                + "FoAUk3NPE5K8ovMPNFtzX27rprTndU0wDAYDVR0TBAUwAwEB/zAKBggqhkjOPQQD\n"
+                + "AwNpADBmAjEAonkaekNeu3ICbZyvbuMIBppBemAdGgTArlVEl+V6BFqhqpAwNwvl\n"
+                + "ipkjYLDTLCNmAjEAofWQz5kSdpigbJCU/ke9JFce9Vy6gp4kPIghN6f6EYtlwQQU\n"
+                + "yXwh67EHeFD4Bnr7\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCpxyn85BJ+JFfT5U7U\n"
+                + "VY+c8v2oY873YOVussMDiC82VYGKZDZH8D6C6h0b33iCpm2hZANiAAR5esh3fLL/\n"
+                + "SYk81dcZeUxJAS8ilLIMJwopB3ZmbWq3SADUdRIe6V9K3IdQjoOX+ljuJHTA7/Fg\n"
+                + "haGKuapP5dtU9NYglvbjkt/0YWJH93pTJRupe42D0amdRGzLlmHHgN8="
+        ),
+        ecdsa_secp521r1_sha512(
+                "EC",
+                /**
+                 * Signature Algorithm: ecdsa-with-SHA512
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 7 08:03:11 2018 GMT
+                 * Not After : Jun 2 08:03:11 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: id-ecPublicKey
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIICATCCAWOgAwIBAgIUPA5KmdGlz29IePn+kPah9OlNRyYwCgYIKoZIzj0EAwQw\n"
+                + "FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNzA4MDMxMVoXDTM4MDYwMjA4\n"
+                + "MDMxMVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIGbMBAGByqGSM49AgEGBSuBBAAj\n"
+                + "A4GGAAQAs1phx3tISw+G2HA8r4ZflQ3Q/5o9U5zeFz79PsKEPSsE1xhGbUyWDasB\n"
+                + "SeUKOvVsli5vYy0hdO132Q7Nl+QANUEARY2ax5ERXIJBY9S+PRdP7OG4fr966Rv8\n"
+                + "vaCE2g8pV9NnAtalN3sk8iCEdVUthvL9R6nopiEd7Fz9SMRGOSu18FajUDBOMB0G\n"
+                + "A1UdDgQWBBTUUVvZJV1MlH/cRuWxfMF9eIsXBTAfBgNVHSMEGDAWgBTUUVvZJV1M\n"
+                + "lH/cRuWxfMF9eIsXBTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMEA4GLADCBhwJB\n"
+                + "UUzp0KbJ1dj1h2xd4yN1DXW+Xyxah8Z5oiWvG1EfTYL201GcgmUhfqqwJBJphtsh\n"
+                + "Bg7qTGGg5F9cVOI9+yMCcDoCQgCJ3chYHlTiC5QpW54hdeV+k45PoCQ62Foopn2i\n"
+                + "N/aUEkWfZ7OidC7O3BWlhDvrHcPLisxHx4oF7vebatReBE+DLQ==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAz7qc9msPhSoh0iiT\n"
+                + "Z0146/sLJL5K+JNo2KdKpZOf1mS/egCCbp7lndigL7jr0JnBRIjk+pmeBtIId6mW\n"
+                + "MrcvF4KhgYkDgYYABACzWmHHe0hLD4bYcDyvhl+VDdD/mj1TnN4XPv0+woQ9KwTX\n"
+                + "GEZtTJYNqwFJ5Qo69WyWLm9jLSF07XfZDs2X5AA1QQBFjZrHkRFcgkFj1L49F0/s\n"
+                + "4bh+v3rpG/y9oITaDylX02cC1qU3eyTyIIR1VS2G8v1HqeimIR3sXP1IxEY5K7Xw\n"
+                + "Vg=="
+        ),
+        rsa_pss_rsae_sha384(
+                "RSA",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 7 08:04:01 2018 GMT
+                 * Not After : Jun 2 08:04:01 2038 GMT
+                 * Subject: CN = root
+                 * Public Key Algorithm: rsassaPss
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDXDCCAhOgAwIBAgIUTYfwEB8SfPXHN+jU18mGBoInoxwwPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogQC\n"
+                + "AgDOMA8xDTALBgNVBAMMBHJvb3QwHhcNMTgwNjA3MDgwNDAxWhcNMzgwNjAyMDgw\n"
+                + "NDAxWjAPMQ0wCwYDVQQDDARyb290MIIBIDALBgkqhkiG9w0BAQoDggEPADCCAQoC\n"
+                + "ggEBANVenkAl6FfHbzw1HG38BAS6tuNBSXU9m5/0kEGP5J5tWqGNVL/zwRoFGPH4\n"
+                + "q1KUpmbE6kgDka5fwBKALlh1mnLbgNG283mc3zj4MDgv+IZvK9D2pJfd8oTmMNqS\n"
+                + "QGwL19tlLjXiq+shwcccOMGJrmAU21Ca+rn/kn+nOjMnhP3mWyR9z/K1PI6D4wvJ\n"
+                + "Kexp54vhuu9dgfBM4d5vlCtnbE5Y5kZHEVhLHbmlR1urnqjlqq7YVl8W4UUaV6CE\n"
+                + "Djj3b6+u+87zjMv9NJh+bn44DPlnnc8WkUIohf8ci4rdUQlT/STkIjl6L1MDSUxC\n"
+                + "3PAjRaTGgpdg3bq81omO1O7OQEcCAwEAAaNQME4wHQYDVR0OBBYEFK6KsXrsGUu2\n"
+                + "IoaQ+Q07G3Vi7AWWMB8GA1UdIwQYMBaAFK6KsXrsGUu2IoaQ+Q07G3Vi7AWWMAwG\n"
+                + "A1UdEwQFMAMBAf8wPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgKhGjAYBgkq\n"
+                + "hkiG9w0BAQgwCwYJYIZIAWUDBAICogQCAgDOA4IBAQBuflWm96V3EvIBfuTcjIq/\n"
+                + "R0AEqNb17F7v96cJHNj1FKM0mFu8R1UBWDYzwNAdXLylDzn/4OEsYmcY2AaLKn9j\n"
+                + "E5IXcMeGTuDX0rsUJtdBu4ueHzr4PUMkEsRHL9vG6EYj12+UyHl1iN2F4dWU6Vvs\n"
+                + "mtKjGZCA2VG2+xczyS1PouLV/H/My7O0cB0eO3kOlMFENcLRMgcwWLvUKuKgzZ2z\n"
+                + "XerJdFBQ1wEJQr9JdcbAXJkQCbiFq/sgdzLuo9KwiQ9WOm99eB//iHQkOiNF0NLn\n"
+                + "hMdqUqaPOvUBl2gVC+aPm0cdlFj1IcbAaOq6Kg2OA3edapyUQF3+jZm4pnPHyT8Y\n"
+                + "-----END CERTIFICATE-----\n",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 7 08:04:01 2018 GMT
+                 * Not After : Jun 2 08:04:01 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIID8DCCAqegAwIBAgIUKNLkRNjNsv7usNhc8tvkJwyKBxgwPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogQC\n"
+                + "AgDOMA8xDTALBgNVBAMMBHJvb3QwHhcNMTgwNjA3MDgwNDAxWhcNMzgwNjAyMDgw\n"
+                + "NDAxWjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n"
+                + "DwAwggEKAoIBAQCe7chGqR+iYpXWHDWK0LZVff4XDc/dS0CloNQr6GAa/Gb7p37v\n"
+                + "kjWStk5BKpRg1SNZtssFNEOXR4phjFf3boUQ7A1i9e+eYJAmbGalwwotY1zxdr5k\n"
+                + "faWYxIiMSaPHHwPfe/pnY1RF6lOsLlegPw6xxg08LETaU+M9QCJ9EodXDEb19/Kw\n"
+                + "INer/Cduou7TdVDFPYY02lMoj7WrvFgu90fRL/EmsMgN6dB9pBS6GbJK5e8E4lpg\n"
+                + "KacuXdCf3eHWMz/4MGKxXEzXTv4kjvR067xjZmtvO70iTQgmL54w1YdLO5oU1yYl\n"
+                + "yXJ/z0iBEM5TG4nESoTWkILZDLcqjyCPfzdXAgMBAAGjgdwwgdkwCQYDVR0TBAIw\n"
+                + "ADALBgNVHQ8EBAMCA/gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFC5n\n"
+                + "8hdp8OS1TWG/EzvMHa1R8608MEoGA1UdIwRDMEGAFK6KsXrsGUu2IoaQ+Q07G3Vi\n"
+                + "7AWWoROkETAPMQ0wCwYDVQQDDARyb290ghRNh/AQHxJ89cc36NTXyYYGgiejHDAR\n"
+                + "BglghkgBhvhCAQEEBAMCBkAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJh\n"
+                + "dGVkIENlcnRpZmljYXRlMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUDBAICoRow\n"
+                + "GAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAqIEAgIAzgOCAQEACnNXDJXG4sneapAr\n"
+                + "U3CjwrNB+ip7v6qTuntIMVxpo5ONMdE0lX8UcAsUfnIaUKpNZxAENelsG7ywdV3R\n"
+                + "unWV28bY4faIrgzKB230KS0GvjQ+gARvaP39V/7r2OtpXfLzMKlddacAQt65G4uB\n"
+                + "9j9pDb6hD2FZvBZLsfuzezl6TGO7mDw61BK61A+9cJLLnHzpR7TdgjKWtZ2FB29P\n"
+                + "zXly+ukq56Xadu9QbDzjnKxrPSzgd2i05C62qBWZ8/0ZvCIcFqEVAa/IReTIwCCo\n"
+                + "805SJ0VB3hOUK8eg/FOT10cK+JPZaSTQxYCUxL9fAaoQB7SnA6MsBXprpq1Ibse6\n"
+                + "zGU9Zw==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCe7chGqR+iYpXW\n"
+                + "HDWK0LZVff4XDc/dS0CloNQr6GAa/Gb7p37vkjWStk5BKpRg1SNZtssFNEOXR4ph\n"
+                + "jFf3boUQ7A1i9e+eYJAmbGalwwotY1zxdr5kfaWYxIiMSaPHHwPfe/pnY1RF6lOs\n"
+                + "LlegPw6xxg08LETaU+M9QCJ9EodXDEb19/KwINer/Cduou7TdVDFPYY02lMoj7Wr\n"
+                + "vFgu90fRL/EmsMgN6dB9pBS6GbJK5e8E4lpgKacuXdCf3eHWMz/4MGKxXEzXTv4k\n"
+                + "jvR067xjZmtvO70iTQgmL54w1YdLO5oU1yYlyXJ/z0iBEM5TG4nESoTWkILZDLcq\n"
+                + "jyCPfzdXAgMBAAECggEAEWKPcvNTK48/NsG1Na8pEucKYXk4UMvHkZarPvZXdPxB\n"
+                + "Q6wJ3akPxTG+E7DVtFX8XPb69GHINwczYwJYKQ/k7Hn16OpgQOHtQta+z8krFtX0\n"
+                + "t9E2eIWqFLEDAt2XVdPVt5+3P5IFCPTeHEqheT0MnXO9xOROz9c3V17ppubc+S+J\n"
+                + "fm5gme7i+nK5tU3r+SFl9BY9YKHHIXamggUJioVtpSQHrZEK6ygBxyKrdKGbS2Ii\n"
+                + "XTvlsvKXePkGUBiKZ6dqkZwPIRFrExObrrGuxp3l6ajTZe5l4/Q8amG6yVvwhOyG\n"
+                + "ASLKr+9TouErnLjty+uGpWgn+YvIdzrligq5dnPmIQKBgQDKNKRByiikoAbvvrmh\n"
+                + "FHelRegG9wsHAe07L0hPgoObj1iq/HKocNpZtu6Qqzm1cAQ+oinACDbf699xIUWC\n"
+                + "V7jEou/d4kdcbJ9b4o5fMj9YNc6XVO34ce9sHkD1CSsOWlgtlfwui2c0y5H2buUw\n"
+                + "dBY9OVRbCQMvgL+UZMmbsHxPsQKBgQDJNb5syiJyWOwI3wZuvVXDAzOXoq7Yn2lP\n"
+                + "E047wPM4d6F3dVBIPlyremHdEhYpUD4mP7d2bO9e9+o0deMqh7vJP/JlangZSUYD\n"
+                + "qXmMpNBwVcZ/n4rfkMInWLy7r1XYgQJ1L1+rVnbTLQPrDa/4+JO5IyBAPTAftXQ1\n"
+                + "xaevCZmBhwKBgHCtdPrUVGGoazUd6wNADIwksG9xKsv03uWkK39jE0OUVayykJIc\n"
+                + "kRB9R+OGBtp8WWEtrGY+LZYKMrEwATPo/iVVRqU2et2eCg+B6CRUM8hL85uQ0Csq\n"
+                + "EmkFUt05Bq0w2wJMGgM124UoC2Zv1XdyuRHU6JTyKLxH2nouz8naRuuBAoGANPws\n"
+                + "GyXXkFkOPv/MB9lf/iyXp3S1qmHAL4yb62xSICqQoI6KB5w0dwuRPdAHefWhiBz7\n"
+                + "SPpCxrVuPUZV/dskfkiSolY5Lh93intUgM7d/Nb5oJ34ygqqtgXOHXZ8mrjOVuGU\n"
+                + "xd/NBqsx/vHpxxxeekBfu8rhI1h7M7XLBHL4s30CgYEAnmwpLxK36H4fyg3FT5uS\n"
+                + "nCJuWFIP8LvWaPm8iDUJ45flOPbXokoV+UZbe7A+TK6tdyTXtfoM59/IsLtiEp7n\n"
+                + "VuE9osST2ZOTD+l10ukIcjJJgI/Pwjtd36EGXyGftdAtT4sFMRxP4sGSXZodqHrZ\n"
+                + "T9fE4yY/E4FyzS7yMeoXIyo="
+        ),
+        rsa_pss_rsae_sha512(
+                "RSA",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 7 08:05:27 2018 GMT
+                 * Not After : Jun 2 08:05:27 2038 GMT
+                 * Subject: CN = root
+                 * Public Key Algorithm: rsassaPss
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDXDCCAhOgAwIBAgIUUpFAFfaMrxI32lmRz/42b2V23C8wPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogQC\n"
+                + "AgC+MA8xDTALBgNVBAMMBHJvb3QwHhcNMTgwNjA3MDgwNTI3WhcNMzgwNjAyMDgw\n"
+                + "NTI3WjAPMQ0wCwYDVQQDDARyb290MIIBIDALBgkqhkiG9w0BAQoDggEPADCCAQoC\n"
+                + "ggEBAMDE8lSB3tzeRr1GW/A1hU+n1zErrqNBjOm/mW2k+eUqfRnCnga9Li82/rA0\n"
+                + "5nSxWb9vHY4M7dr82lhNBt/AdQB7nkDmD1BDWnuQuDTrhIFTvHjh802KUJT8sz/G\n"
+                + "xXMXYxvK7kQPIuW+1xNxZirwnwLLZ7uo7WlvFqgMsYPJQ2+qREWRBgsj2BiDs90x\n"
+                + "2Cc7YqRBAMglmT/NsqJoK7RZqAfhLEn1KYSkou7C4Fx32qc4RQGuUQzfTXMX1UGT\n"
+                + "fjU1i7IcY0eY1Ed+VFPUI6Kl/aeFSfal+/Lz2siq8CT2fLxXwGtM/YtaOdQhCuvV\n"
+                + "ekmntL7KalQS32f681qaccFTmSUCAwEAAaNQME4wHQYDVR0OBBYEFM1g6dCfIEe1\n"
+                + "3kE2spDLZe4xbN3KMB8GA1UdIwQYMBaAFM1g6dCfIEe13kE2spDLZe4xbN3KMAwG\n"
+                + "A1UdEwQFMAMBAf8wPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQMEAgOhGjAYBgkq\n"
+                + "hkiG9w0BAQgwCwYJYIZIAWUDBAIDogQCAgC+A4IBAQAMa7OlZheye0Km/f4+95St\n"
+                + "WXWYUhMuBHo2G/goFhCFEYtHiJa2B/e+14lPq+95xMLJ8kQRxQolG/brOIDeUwdx\n"
+                + "85Pqfx50UnoZUhE+d5iJAJPHiS5aUoYa1Nxu7pw7eC402imkZt/P5OmPU1B9LTql\n"
+                + "Mizo7guIVyXOXE11iOSFXfUk3q0XxErBzEIQmZDQjbv2idWPuTJV5G/Mo3dm+Oiq\n"
+                + "6JTWKzCMp2pMFvUllP0FNEzIc1Q5qTkwFCzf8d5NLVa143kWuU0G9VbAjAJaEEfa\n"
+                + "PUlfJQzkEKn0MsGWkpYMepbF4z7FB37jrLaHgHZvxpX1dXg8NWOqBXGSD154hzpf\n"
+                + "-----END CERTIFICATE-----\n",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = root
+                 * Validity Not Before: Jun 7 08:05:27 2018 GMT
+                 * Not After : Jun 2 08:05:27 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsaEncryption
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIID8DCCAqegAwIBAgIUP97IqgwiXunHNhSojyU10fxkvz0wPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogQC\n"
+                + "AgC+MA8xDTALBgNVBAMMBHJvb3QwHhcNMTgwNjA3MDgwNTI3WhcNMzgwNjAyMDgw\n"
+                + "NTI3WjAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n"
+                + "DwAwggEKAoIBAQDCyeGmgpaHoXnRcsuhMhzsoinxDqSCHfJB62g0HuZDpZG3yjlE\n"
+                + "U9zVTLeuCtWsrQnC0LCaNODjjvE9vI1tbY5L7B1pz3JNHrASzituzd3vPNlKjX5f\n"
+                + "EUG4dBEOIx0UvwTDlf8taL897aLRmUHKE29qPV3Xo80M794CdQsUSq/sNQDkE1qF\n"
+                + "m7MAmznXTS++RUqtofyz4W570KBwfM9pO4hFd20JvjkumadXY1dJbt99LyO3LVZd\n"
+                + "QsztBe5meWElFcQJj/GdkSGFlrEGpePgwQ6U5MCrWDQonX1JX3aIiby4EFZrvdCK\n"
+                + "r15pBpCEowoV57KDIzkROV2vRyYfjO+E5AUHAgMBAAGjgdwwgdkwCQYDVR0TBAIw\n"
+                + "ADALBgNVHQ8EBAMCA/gwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFIZl\n"
+                + "PBtklckudi3unnRw45td3lYOMEoGA1UdIwRDMEGAFM1g6dCfIEe13kE2spDLZe4x\n"
+                + "bN3KoROkETAPMQ0wCwYDVQQDDARyb290ghRSkUAV9oyvEjfaWZHP/jZvZXbcLzAR\n"
+                + "BglghkgBhvhCAQEEBAMCBkAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJh\n"
+                + "dGVkIENlcnRpZmljYXRlMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUDBAIDoRow\n"
+                + "GAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCA6IEAgIAvgOCAQEAEAhEFgf7PkNrqB/e\n"
+                + "IWs6LbXmSWS6h9iv/7m42AsxslBXqvyFLLmKcl8g1yowgUPP3Wp4tBWU8F5OHgbQ\n"
+                + "KdGJVXsrw+5Dlj5joXUisiEnG10nDr+i6qMx8k0U+K2qzBPTyAGkK5CadY04AquX\n"
+                + "3EBWnUIzXSX+5quBR94g+okKC+lyiwtoq7uJrIA4I4buikgsKWHNIU/3DqcI54fb\n"
+                + "ty1bWgW1CP48dShs0phZs8k716L0J9Gfz1fkhb1czAZikcecitt5GrbAUj9GDq1Q\n"
+                + "1zjvjQiPXaZFXiDVmUUEVUsVDFtEuwiMKRxpprXEWklbQnOcWONCRy3113DdWauX\n"
+                + "ECtlAw==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDCyeGmgpaHoXnR\n"
+                + "csuhMhzsoinxDqSCHfJB62g0HuZDpZG3yjlEU9zVTLeuCtWsrQnC0LCaNODjjvE9\n"
+                + "vI1tbY5L7B1pz3JNHrASzituzd3vPNlKjX5fEUG4dBEOIx0UvwTDlf8taL897aLR\n"
+                + "mUHKE29qPV3Xo80M794CdQsUSq/sNQDkE1qFm7MAmznXTS++RUqtofyz4W570KBw\n"
+                + "fM9pO4hFd20JvjkumadXY1dJbt99LyO3LVZdQsztBe5meWElFcQJj/GdkSGFlrEG\n"
+                + "pePgwQ6U5MCrWDQonX1JX3aIiby4EFZrvdCKr15pBpCEowoV57KDIzkROV2vRyYf\n"
+                + "jO+E5AUHAgMBAAECggEABOg3Eg3KIwKTYg5lSNtNVTzEl7kJtelxN+3pQx7gKCYc\n"
+                + "pKeoh6shLhJvsie9uErnqwu81zWr0K/CLg749R/EbO820nqSY5T5VI/zEiiHhcZf\n"
+                + "pvwnideSc0YhQ9zol6Q0R4UY15kC8FlzN5qHyMJylReUrKEIwmGskx1FuS4kfmvQ\n"
+                + "JYx7pzrVYAVtktIEz7BSsN9t0Gigtj20DoT8g9W+pcXRxmiLzJ3pYOe8n7oHcZGf\n"
+                + "cPzT4IYWIHeFfzX6XPoNMUocPU94P/POlRAKYv3vRPqFhHjPq/WCWGhGvAQ7vzKT\n"
+                + "UNCuFP1FyDGTsD6S/qsBxJ5f8WGYncJAxv6iR0hVOQKBgQDp3nFoEiDdSvfTAabW\n"
+                + "64y+pp6U1VxjecR9VOpiUQOCriXefyyqgJIVtQI3CM8igMenHQtFBkcQB+GXnl9I\n"
+                + "2d3a/AOWozFdWWEf+VOcHSo0WY2tqs2WSgiTPzThMLXAfqF0e5SK9nOw5Y8YcQDJ\n"
+                + "bn+5n7rtjxq3O7SBXGH7sGUJRQKBgQDVOLQ2aSupYraJX7bXFdcI0X/3KuUBQnyp\n"
+                + "qcDIc4Ho00DhdjTM/Nf3iRZOY0Fv1GOb1Dzp5pKCCuAeiYpEfgNR0aYrAABRrL4+\n"
+                + "lOZyFvXcueZFPeSuzm17fyNtwgwnG8RlDmXqTSlqnIfEs+wti1cojI2Tpdq8QnCa\n"
+                + "VcnYFnSr2wKBgANj3BT8HknW6ly+q2J2K6Yf2DCkHyC6BSUj8/nU3s4oJBhjk4wt\n"
+                + "LPDvnMabdBU19K7xdtZbTvBmjNibzRnLPrIL8Slf2DlYMFY8UP/0VEZJ/gnEbhJ9\n"
+                + "pD4uLmANSrUtoL2FhRO2mtq3mSlrie1hkqxoKleDOYnqbaVqZ2k0l2JZAoGBALi2\n"
+                + "JLg2J9LXZxZeyoBNtTk4dEjk6fpLZL9+BTohhlryF3S5+EfUiiswoRhLN/bu4VOv\n"
+                + "aw2d5zGsxjbuI8/t8mZA3ljF6YDXyv9f8rrHVTpf+THmymL9BS9FFqYQwoJmtZ5t\n"
+                + "+LAfJE/tRliLHYDfAyRnjoZn2bPZQr8Qroj5+xydAoGACHEc7aoEwZ/z8cnrHuoT\n"
+                + "T0QUw6HNlic5FgK+bZy7SXj9SqJBkWADzRJ/tVDopWT/EiDiGeqNP/uBPYt6i7m2\n"
+                + "SoqCLYdGDIbUFyDQg3zC48IXlHyEF3whx0bg/0hoKs/E/rXuxYIH/10aEwmb0FQO\n"
+                + "GA3T726uW8XrrTssMkhzixU="
+        ),
+        rsa_pss_pss_sha384(
+                "RSASSA-PSS",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 7 08:06:30 2018 GMT
+                 * Not After : Jun 2 08:06:30 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsassaPss
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDZjCCAh2gAwIBAgIUA5CP0rop4wp/QliNQrIiWzepcncwPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgKhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAICogQC\n"
+                + "AgDOMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA2MDcwODA2MzBaFw0zODA2\n"
+                + "MDIwODA2MzBaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASAwCwYJKoZIhvcNAQEK\n"
+                + "A4IBDwAwggEKAoIBAQDP7X9JUp1rPzcxyzpHOS4jJm/AOhgJC5ueK54wn+ZwxIk4\n"
+                + "hAjHGDGsUIfxzDmMW7nCxvmw/BV0xfAqCdLRYd1Id9cMuNiPYiDu/LC10rMRbdFl\n"
+                + "0GQvnaqXGLb0EJETJiEWiYemljswr4E3hzeKk6Z2dXD4WhUl9M+4ACjB5hGDTUD0\n"
+                + "sKYMMtjRfz1TVUtgnbzqHMc0dZFY7BVCIoOGDtXpZbQTHeuMFt+X6WWoYbpe62S/\n"
+                + "+lPe1Jj4WqQyRaiJ9wBUvF1jxZughLfggTUH+bIFqKEPTsZTY/GF5Tw0devRbkjr\n"
+                + "7iiwKWZUqrw0gQNvfpMHkJ20vl88NIUTskx+ehXRAgMBAAGjUDBOMB0GA1UdDgQW\n"
+                + "BBTk0W52uedFo2XRMmO+vjCb1HxgVTAfBgNVHSMEGDAWgBTk0W52uedFo2XRMmO+\n"
+                + "vjCb1HxgVTAMBgNVHRMEBTADAQH/MD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUD\n"
+                + "BAICoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAqIEAgIAzgOCAQEAMubCeSw/\n"
+                + "XnF+EYmLt3Vj/1CRbqCG46VUYYGqFsIDB36q2Vate2UMeOMbBXNldNLWS6QWHPhv\n"
+                + "wJR72OcviVh7twH3qDd6jBzkt6jiwXyeSZeCu7g8p6RhtoUT7pxSm/f7aQ+SQRNT\n"
+                + "+XX1E4pakzEmyvCzyFzm6i7ol/KhZKI3bycUNMmNldE/TmDAwQLI2I6ld/jlQ4Yl\n"
+                + "qQd2af1P7T19898EkA0Ka1LYRVNzlAz40rQc9Nw5etq2vuXMg9U229KZvT6qikWD\n"
+                + "4V4xzTMfn2l+yfrHU6XGUawJoDds1dy03hrveYH90PKboQaPEOAn3MPjNlZF21Dl\n"
+                + "Ukj3JA+ZxAZmcw==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEAz+1/SVKdaz83Mcs6\n"
+                + "RzkuIyZvwDoYCQubniueMJ/mcMSJOIQIxxgxrFCH8cw5jFu5wsb5sPwVdMXwKgnS\n"
+                + "0WHdSHfXDLjYj2Ig7vywtdKzEW3RZdBkL52qlxi29BCREyYhFomHppY7MK+BN4c3\n"
+                + "ipOmdnVw+FoVJfTPuAAoweYRg01A9LCmDDLY0X89U1VLYJ286hzHNHWRWOwVQiKD\n"
+                + "hg7V6WW0Ex3rjBbfl+llqGG6Xutkv/pT3tSY+FqkMkWoifcAVLxdY8WboIS34IE1\n"
+                + "B/myBaihD07GU2PxheU8NHXr0W5I6+4osClmVKq8NIEDb36TB5CdtL5fPDSFE7JM\n"
+                + "fnoV0QIDAQABAoIBAGB1eh5G0DaHnhBgikmuUiQGWcNgb/QKSYgoDfvawinAUzQ/\n"
+                + "tF7Ab5LTzS00I+JkTxn3+q/LUhzZEqA97GosL17GEaKaQgTKbiLQYR4If//u5TyJ\n"
+                + "X2DjkNcFpSI2aUbr4l+1L5Ptj8n3MUfUV8TW2FuOAfmEuNjh6Fcg48eH9snk/wTI\n"
+                + "8yvQPODnEaW/9MucySd0LJK3YX+rRa5EG3kJry+FmdMBzaLrCOInq/j1P7wXmlBc\n"
+                + "6Jpynhu/HzYjbk9s3xqUHckX1+DLfzpIEFqXJF0YjswiV2EEP2YLt2OYDP4X8M2X\n"
+                + "zfZ4l2ArHcfPZwy2/chui+VAm4bNPsYjDeqMHC0CgYEA+6ujKrhYx8mjiaqmYStR\n"
+                + "KZvmy5sL3GQEpZ3y6s7JNKW+h6z75USlRQYRGG1L9DRyEtfkuYzvzZwVR+ermGJb\n"
+                + "XvHIBDdgDmurORHqYGVywfqfo+5KM1GAMeDvBW0LeGoZIYOdno2q/lnNm1kX/g4d\n"
+                + "VBMiurHeNkOdJXSgNc7EZ6cCgYEA04E3PxU12Xs3N2/ZoEYcAnEm6zbljt8fc/CG\n"
+                + "gyRfGWb6RzIF9oKmLENhcNWpX+7hk2HsUZmQlmTofF7JwF/UBkySWclNXnO2OQwd\n"
+                + "AGF+WXQwACVg3S2X/y5Pu+8JpaEJdyahuynSuBmxyjavFBTDkI02Heu5ZSwVN6Fp\n"
+                + "tYDmxccCgYEA+Kfs3xilH0CqxCpHmVojJulSb3kRjv+DV99nU3hcdBgO2B6iAzR/\n"
+                + "1mLYITpcATyQOO32nx4RESVWIWVUtYr4nCZnaUMNNTJMSmbZG8UgTWhCssWNqoas\n"
+                + "EpwbjVDgNGkfy20vHqj6ebRg4Ux12B45/AesGKoE07iaW5ePc5qHk6ECgYBpeSS9\n"
+                + "1qv1+pY8lRCn9o59QUQxRD0SFH6w6J+LwpWSK2JgIrgKiHip1ig/hq1iY9QmFU0u\n"
+                + "HDCYb1Xov7RItQEc6w6Iq/RjR7z1ke7cg8HohiJx0DIP2m7UGJo2lCvxZu87dg5t\n"
+                + "MZwdpuKcfsysbPZhnaoBHc5kf6lNBreahd+PfQKBgQDzZHFUndVfI28zn10ZzY8M\n"
+                + "zVeUMn+m1Dhp/e4F0t3XPTWCkwlYI3bk0k5BWHYSdLb2R7gKhTMynxPUb53oeY6P\n"
+                + "Pt/tA+dbjGHPx+v98wOorsD28qH0WG/V1xQdGRA9/dDZtJDolLqNn2B3t0QH9Kco\n"
+                + "LsJldTLzMQSVP/05BAt6DQ=="
+        ),
+        rsa_pss_pss_sha512(
+                "RSASSA-PSS",
+                /**
+                 * Signature Algorithm: rsassaPss
+                 * Issuer: CN = localhost
+                 * Validity Not Before: Jun 7 08:07:22 2018 GMT
+                 * Not After : Jun 2 08:07:22 2038 GMT
+                 * Subject: CN = localhost
+                 * Public Key Algorithm: rsassaPss
+                 */
+                "-----BEGIN CERTIFICATE-----\n"
+                + "MIIDZjCCAh2gAwIBAgIUCoYfs6/TS3M2xgZYjN2Ke4LPEOwwPgYJKoZIhvcNAQEK\n"
+                + "MDGgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIDogQC\n"
+                + "AgC+MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA2MDcwODA3MjJaFw0zODA2\n"
+                + "MDIwODA3MjJaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASAwCwYJKoZIhvcNAQEK\n"
+                + "A4IBDwAwggEKAoIBAQDG/9pbt7MT6Be3aUg94VKQ9BMojLYjBDzM7bd/y07+Lfdd\n"
+                + "67IUhQ5VkJcxgs7Qtb8ztnUJQEzyLBkcZA/hvvpLUXJUP3UisRNV12MBfHUcFAVN\n"
+                + "33pdm7X/UJDVadUZTAfe6PUIuk/+ZpOmTnwE/sEfhCZAtNwm+08EdysUhK9aVl83\n"
+                + "vC+eEj22584Vzd2fQj9YYU1hN0OKWvavrHvc3XCjam15UCWBZa1ujXnjOtYkPDE6\n"
+                + "0C/BS+WE/GtLGGc04O410/ezvs/M66RdlMFJRBLW3F9grL2oG41CmoLzFaPL6AOD\n"
+                + "W2EYBf094uvreR7mDlr8MCmig4+IHCpdwmbbYrhjAgMBAAGjUDBOMB0GA1UdDgQW\n"
+                + "BBSZnv73VPYJzx4m2n0xIYHRL+avKDAfBgNVHSMEGDAWgBSZnv73VPYJzx4m2n0x\n"
+                + "IYHRL+avKDAMBgNVHRMEBTADAQH/MD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZIAWUD\n"
+                + "BAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCA6IEAgIAvgOCAQEAeHFMR7gi\n"
+                + "hcd7acEBc4Qw+JCH81+8PAwfCH+7uMbLronUDmHPgeMckNvGGEFenDDp+pqnpiFN\n"
+                + "pKdDpelv4lkE72gFGVpEGlrCjVrwJSyPR26Dju9Nx+WQCQIiTUGd03fBgxb+rh5U\n"
+                + "kvauleAa7Xb0TkpWawfe2RadfAwSHcdwYGVA5Rh1dTfn5Chz8fdt5y6tFcLnJpgY\n"
+                + "tvHk5Z5hFTgsDpdTv/aKcUypsQDnBmCaAot3S9ks3FBea/g/ACrqi/Td8OaHr9/W\n"
+                + "wLnBvPtd++XvAFMaZKrMfjIzlmQyHfLQ/4EA9PPOK9DqBkUcnvcSLH6TL57yoDB6\n"
+                + "h6/Ppk90DH6vhA==\n"
+                + "-----END CERTIFICATE-----\n",
+                //
+                // Private key.
+                //
+                "MIIEvAIBADALBgkqhkiG9w0BAQoEggSoMIIEpAIBAAKCAQEAxv/aW7ezE+gXt2lI\n"
+                + "PeFSkPQTKIy2IwQ8zO23f8tO/i33XeuyFIUOVZCXMYLO0LW/M7Z1CUBM8iwZHGQP\n"
+                + "4b76S1FyVD91IrETVddjAXx1HBQFTd96XZu1/1CQ1WnVGUwH3uj1CLpP/maTpk58\n"
+                + "BP7BH4QmQLTcJvtPBHcrFISvWlZfN7wvnhI9tufOFc3dn0I/WGFNYTdDilr2r6x7\n"
+                + "3N1wo2pteVAlgWWtbo154zrWJDwxOtAvwUvlhPxrSxhnNODuNdP3s77PzOukXZTB\n"
+                + "SUQS1txfYKy9qBuNQpqC8xWjy+gDg1thGAX9PeLr63ke5g5a/DApooOPiBwqXcJm\n"
+                + "22K4YwIDAQABAoIBADoeFuOabs5thh+mu9Z2q+pxnfbFwZvQbQFcm67S7asGOaxQ\n"
+                + "XZ3ojhsnM0DedxA1RDYSH3QoN1Cy2FKWVp0TbX35t24rakZLeN4lHWEdvAYLQtFP\n"
+                + "ZylXhHugR+xMEFRnBBVx6740y4/83TpAya+bx0MxEQrsxy8LTjR7qTVA2wWCmDur\n"
+                + "n2wzt7axGGBWq0/4n62aRszhAYDVIa6EXI2UAcGQwdWuw4iiVRjdEVc6I/W3GA62\n"
+                + "a+RlhA1LPcNkAiONVoVhBCFxSZq+ERuupS31mVjbGEDlOUDw0XfrJb3n4ekXbN4C\n"
+                + "6EHCbBA6DPr9FrMT6dgqpTfnsF26rQp2kgLrngECgYEA6UpueG7YvwQxi+vq3tGS\n"
+                + "7FldARE2obWrGDVbm+WA1TlnOwQDyCZPTSYFtNkBoqZtFzVZsM8mjYu8vDnrCuVN\n"
+                + "DmthBwbH2LYQXVXeZhaZVCF6QWP77OWLrlEVlhbHHG0xdgzgP5cNJWe56JpQZW3C\n"
+                + "GIbmmsSE8jIYgjh5MBAxlSMCgYEA2l7jGeUw/U017FRg/mTFbLM74Tc7/GHyVinF\n"
+                + "MouM+v+erXoNRXL6KH43RoHbiFhfDD9e67pu2O0BsHn2BUV5GKAi4hcyoYqi1h7h\n"
+                + "oGtk1DyFCcOV+6NzUqe72RrTv1868K/j2sRmfqtU3gNlKFId+CUVYGUEjK2pNDHd\n"
+                + "IvqEo8ECgYApqoKKffm2PBCBVhRv0Wx1TAyhWSqxvRmezEDdWiMlcggu8Sufvr/h\n"
+                + "Ho5cW3nATAsl3wBy5LyVAUUnNQz2uDeIAMOmlp5w5SuND/4Vq6mc7hHAxhPDnsfQ\n"
+                + "zWiWkuDjAdmYpPoUQW02pgz9Lzp2syC8crOTJtA71ZitAVsbq3i/kwKBgQC550ft\n"
+                + "drnTGxVKAbelO0L7vEbBABXYUcZOZjcURcuar112EE8WDcE8Ed+a7dhoZdtdAOId\n"
+                + "StUtZfAnPl0ctb1XIpUv51HaRr1EDnxE5sirCm60FkcsOEVoW5XHSVh1NmxmFUek\n"
+                + "qckcE14nt7o5rlcHNwLQ0o8h+IHxBnZdXernwQKBgQCunOWvYd7MGlIjpkl6roq7\n"
+                + "MrQ/zaAkUyGsTgBxEu3p5+x2ENG6SukEtHGGDE6TMxlcKdTSohL2lXZX2AkP+eXf\n"
+                + "sF3h66iQ8DrGrYoyCgx3KTx3G+KPfblAqwDMTqj2G5fAeWDwXrpEacpTXiFZvNAn\n"
+                + "KtqEurWf+mUeJVzLj1x1BA=="
+        );
+
+        private final String keyType;
+        private final String trustedCert;
+        private final String endCert;
+        private final String privateKey;
+
+        private KeyType(String keyType, String trustedCert, String endCert,
+                String privateKey) {
+            this.keyType = keyType;
+            this.trustedCert = trustedCert;
+            this.endCert = endCert;
+            this.privateKey = privateKey;
+        }
+
+        private KeyType(String keyType, String selfCert, String privateKey) {
+            this(keyType, selfCert, selfCert, privateKey);
+        }
+
+        public String getKeyType() {
+            return keyType;
+        }
+
+        public String getTrustedCert() {
+            return trustedCert;
+        }
+
+        public String getEndCert() {
+            return endCert;
+        }
+
+        public String getPrivateKey() {
+            return privateKey;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/TestSessionLocalPrincipal.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+/*
+ * @test
+ * @bug 8206355
+ * @summary Test principal that was sent to the peer during handshake.
+ * @run main/othervm TestSessionLocalPrincipal
+ */
+public class TestSessionLocalPrincipal {
+
+    public static void main(String[] args) throws Exception {
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        for (String tlsProtocol : new String[]{
+            "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1"}) {
+            for (boolean clientAuth : new boolean[]{true, false}) {
+                System.out.printf("Protocol %s: Client side auth enabled: %s%n",
+                        tlsProtocol, clientAuth);
+                CountDownLatch serverReady = new CountDownLatch(1);
+                Server server = new Server(tlsProtocol, clientAuth,
+                        serverReady);
+                server.start();
+
+                // Wait till server is ready to accept connection.
+                serverReady.await();
+                new Client(tlsProtocol, clientAuth, server.port).doClientSide();
+                if (server.serverExc != null) {
+                    throw new RuntimeException(server.serverExc);
+                }
+            }
+        }
+    }
+
+    public static class Server implements Runnable {
+
+        private volatile int port = 0;
+        private final String tlsProtocol;
+        private final boolean clientAuth;
+        private final CountDownLatch latch;
+        private volatile Exception serverExc;
+
+        public Server(String tlsProtocol, boolean clientAuth,
+                CountDownLatch latch) {
+            this.tlsProtocol = tlsProtocol;
+            this.clientAuth = clientAuth;
+            this.latch = latch;
+        }
+
+        public void start() {
+
+            ExecutorService executor = null;
+            try {
+                executor = Executors.newCachedThreadPool(new ThreadFactory() {
+                    @Override
+                    public Thread newThread(Runnable r) {
+                        Thread t = Executors.defaultThreadFactory()
+                                .newThread(r);
+                        t.setDaemon(true);
+                        return t;
+                    }
+                });
+                executor.execute(this);
+            } finally {
+                if (executor != null) {
+                    executor.shutdown();
+                }
+            }
+        }
+
+        /*
+         * Define the server side operation.
+         */
+        void doServerSide() throws Exception {
+
+            SSLContext ctx = getSSLContext(tlsProtocol);
+            SSLServerSocketFactory sslssf = ctx.getServerSocketFactory();
+            SSLServerSocket sslServerSocket
+                    = (SSLServerSocket) sslssf.createServerSocket(port);
+            port = sslServerSocket.getLocalPort();
+            System.out.println("Server listining on port: " + port);
+            sslServerSocket.setEnabledProtocols(new String[]{tlsProtocol});
+            /*
+             * Signal Client, the server is ready to accept client request.
+             */
+            latch.countDown();
+            try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept()) {
+                sslSocket.setNeedClientAuth(this.clientAuth);
+                sslSocket.setSoTimeout(5000);
+                try (InputStream sslIS = sslSocket.getInputStream();
+                        OutputStream sslOS = sslSocket.getOutputStream();) {
+                    sslIS.read();
+                    sslOS.write(85);
+                    sslOS.flush();
+                }
+            } finally {
+                sslServerSocket.close();
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                // Print the exception for debug purpose.
+                e.printStackTrace(System.out);
+                serverExc = e;
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    public static class Client {
+
+        private final int serverPort;
+        private final String tlsProtocol;
+        private final boolean clientAuth;
+
+        public Client(String tlsProtocol, boolean clientAuth, int serverPort) {
+            this.tlsProtocol = tlsProtocol;
+            this.clientAuth = clientAuth;
+            this.serverPort = serverPort;
+        }
+
+        void doClientSide() throws Exception {
+
+            SSLContext ctx = getSSLContext(this.tlsProtocol);
+            SSLSocketFactory sslsf = ctx.getSocketFactory();
+            try (SSLSocket sslSocket
+                    = (SSLSocket) sslsf.createSocket("localhost", serverPort)) {
+                sslSocket.setEnabledProtocols(new String[]{this.tlsProtocol});
+                Principal principal = sslSocket.getSession().getLocalPrincipal();
+                if (this.clientAuth && principal == null) {
+                    throw new RuntimeException("Principal can not be null");
+                }
+                if (!this.clientAuth && principal != null) {
+                    throw new RuntimeException("Principal should be null");
+                }
+                try (InputStream sslIS = sslSocket.getInputStream();
+                        OutputStream sslOS = sslSocket.getOutputStream()) {
+                    sslOS.write(86);
+                    sslOS.flush();
+                    sslIS.read();
+                }
+            }
+        }
+    }
+
+    // get the ssl context
+    protected static SSLContext getSSLContext(String tlsProtocol)
+            throws Exception {
+
+        // Generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // Create a key store
+        KeyStore ts = KeyStore.getInstance("PKCS12");
+        KeyStore ks = KeyStore.getInstance("PKCS12");
+        ts.load(null, null);
+        ks.load(null, null);
+        char passphrase[] = "passphrase".toCharArray();
+
+        // Import the trusted cert
+        ts.setCertificateEntry("trusted-cert-"
+                + KeyType.rsa_pkcs1_sha256.getKeyType(),
+                cf.generateCertificate(new ByteArrayInputStream(
+                        KeyType.rsa_pkcs1_sha256.getTrustedCert().getBytes())));
+
+        boolean hasKeyMaterials = KeyType.rsa_pkcs1_sha256.getEndCert() != null
+                && KeyType.rsa_pkcs1_sha256.getPrivateKey() != null;
+        if (hasKeyMaterials) {
+
+            // Generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(
+                            KeyType.rsa_pkcs1_sha256.getPrivateKey()));
+            KeyFactory kf = KeyFactory.getInstance(
+                    KeyType.rsa_pkcs1_sha256.getKeyType());
+            PrivateKey priKey = kf.generatePrivate(priKeySpec);
+
+            // Generate certificate chain
+            Certificate keyCert = cf.generateCertificate(
+                    new ByteArrayInputStream(
+                            KeyType.rsa_pkcs1_sha256.getEndCert().getBytes()));
+            Certificate[] chain = new Certificate[]{keyCert};
+
+            // Import the key entry.
+            ks.setKeyEntry("cert-" + KeyType.rsa_pkcs1_sha256.getKeyType(),
+                    priKey, passphrase, chain);
+        }
+
+        // Create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ts);
+
+        SSLContext context = SSLContext.getInstance(tlsProtocol);
+        if (hasKeyMaterials) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            context.init(null, tmf.getTrustManagers(), null);
+        }
+        return context;
+    }
+}
+
+enum KeyType {
+
+    rsa_pkcs1_sha256(
+            "RSA",
+            /**
+             * Signature Algorithm: sha256WithRSAEncryption
+             * Issuer: CN = localhost
+             * Validity Not Before: Jun 4 15:22:04 2018 GMT
+             * Not After: May 30 15:22:04 2038 GMT
+             * Subject: CN = localhost
+             * Public Key Algorithm: rsaEncryption
+             */
+            "-----BEGIN CERTIFICATE-----\n"
+            + "MIIDBjCCAe6gAwIBAgIUc8yTYekR2LuXkkCJYqWlS/pBMKIwDQYJKoZIhvcNAQEL\n"
+            + "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTE4MDYwNDE1MjIwNFoXDTM4MDUz\n"
+            + "MDE1MjIwNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF\n"
+            + "AAOCAQ8AMIIBCgKCAQEA2jDPGMogc9dq2w5b+FHqbfaGPokRmyObiU8y/l/dqkM5\n"
+            + "9IV+qj8VQUI4NtpdCTWr16812z4AjXrk5HIBrECfQbHPUcm1rme5YVZ0WxV0+Ufy\n"
+            + "hDmrGwDLhkxGqc3hOhRrlF2wdXeUfjIzhvS9+S/401++t/jvq+cqFF1BHnzYOu+l\n"
+            + "nbi/o95Oqo8MlwiRqg3xy3fNRfqXk7DWy+QT8s+Vc3Pcj1EW6K0iJJ23BVTdv6YT\n"
+            + "Ja5IKiWL4XsLht3fWvZwF+PoYfKb+JYflt0rafpxg9xkowe7GnGh2SpV7bJaH/QN\n"
+            + "3PTFEKQWgWHjWwjR171GOzSaEgaklvKde6+zNWeYKwIDAQABo1AwTjAdBgNVHQ4E\n"
+            + "FgQUqCtGe8/Ky4O6pH7xeTUy9yrv4n0wHwYDVR0jBBgwFoAUqCtGe8/Ky4O6pH7x\n"
+            + "eTUy9yrv4n0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAuqch30im\n"
+            + "M09sARarbfK3OExqYK2xoyuUscgTqQNDpNL2gMdXY9e0lTmGVgw9pVYtNZPZRxem\n"
+            + "jR5an2XegvG9qVU6vLENDwLCqZgsTb2gvmXngiG8NVcYd81GNqD228mkgBosNJku\n"
+            + "6BR+C8zlURzsNEt657eVvIp9ObGomdAbWhpdqihBD180PP18DIBWopyfHfJtT5FA\n"
+            + "U2kSPBp+P1EtdceW0zfwv3rF8hwRbnQBzuoYrZfn2PiMYaGUqOgbqUltCMD/Dp9G\n"
+            + "xK0nfAXEwIqHWWnijGwAd6YrszMjBUcSGmlehdF+XZK6jHNlw64RB4WTfavr+rY0\n"
+            + "dTe6g4o5GYr9nQ==\n"
+            + "-----END CERTIFICATE-----\n",
+            //
+            // Private key.
+            //
+            "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDaMM8YyiBz12rb\n"
+            + "Dlv4Uept9oY+iRGbI5uJTzL+X92qQzn0hX6qPxVBQjg22l0JNavXrzXbPgCNeuTk\n"
+            + "cgGsQJ9Bsc9RybWuZ7lhVnRbFXT5R/KEOasbAMuGTEapzeE6FGuUXbB1d5R+MjOG\n"
+            + "9L35L/jTX763+O+r5yoUXUEefNg676WduL+j3k6qjwyXCJGqDfHLd81F+peTsNbL\n"
+            + "5BPyz5Vzc9yPURborSIknbcFVN2/phMlrkgqJYvhewuG3d9a9nAX4+hh8pv4lh+W\n"
+            + "3Stp+nGD3GSjB7sacaHZKlXtslof9A3c9MUQpBaBYeNbCNHXvUY7NJoSBqSW8p17\n"
+            + "r7M1Z5grAgMBAAECggEAHs/7vw10TcejEHJTrJqs14CT7qresKDzqw1jLycMn6nE\n"
+            + "unJLs/EaqE+Yrq5hqxZIQTo+CcsUuuYbAuPStqedleJtW6h3nryJImTaI67BCR8O\n"
+            + "8XtPXY3cMAf/hqVLZC9UDey5Ka2Ma9HdEvbnCRSsN/VycnqWJhmMCLouowaQZqoE\n"
+            + "VopscUix8GqELv0vEo2CszZfUjtSVbNTlNgwDf5U7eSKXMuFsnSn/LE7AMvHsEyo\n"
+            + "HatxogwlM/WjpTnf/WIeJY3VhaK10IsP6OEgUn/p4VtI2DQ/TJdgYrvD5vhjY8ip\n"
+            + "XuUPuPILRvJWo8dRXJqa4diXB12q5YhP8iiOp4BgkQKBgQD1GtlOR+JVgOzpQ11h\n"
+            + "s5/iJOsczee80pQscbSRJnzSsIaP9WM8CyJgvbPxIQxLUQeYnxM/bxNKkpJtzxRK\n"
+            + "pob+v4NoRn8PTpqbOp1obmWJT7uHTaoeavQo7r7uZI4i3eEgHCCQkMzpqzz7UFTY\n"
+            + "2Yst7bBTPUivlSVQQBEc8bLpeQKBgQDj47EjpAlh8DmJRTElg58t+XJehXGTqmlx\n"
+            + "nYu8DQLSzGbOQ/Z4srakC1mkM0LHCmULIIWk3KhV1GBCeArv7DlZ9A1SkI95bsq9\n"
+            + "GBeQpovL0PXKkOOWMJBklP/CTECO4eyA8r6c1d8wytBb6MrJ8bi74DdT+JlFjK5A\n"
+            + "zNoeNx6JwwKBgQCehIPABeuSYvRVlDTDqFkh98B6+4wBaatc5xjhuyOFW5dbaVeJ\n"
+            + "kKXmLSpAK6B44WnpQhA/uUWfuBWtoPy9nt+1yARjnxwzuSFyfUEqNiPC32coBYmd\n"
+            + "bIyGIIopQa1PTXJ4wtgoxw1PnmitHHITYPaLeKrN2te0fuAH+7dVodeU+QKBgAct\n"
+            + "VJbaw7Dh7+3yz+lui8TW5lMzwK/13fxGCfCSOFSLO3Gjkk+a0UW5VclmE+RQ333K\n"
+            + "OGtIx8RsO9vcC/wiZGwA06qWAu7AHoJ2D8fudtikbBlFFuXUAbgpOSTVYfMeCmTF\n"
+            + "QFuQIMdYm9dJLZnOkxLXrOZoHeui0poX2Ya6FawhAoGAAI/QCyDbuvnJzGmjSbvl\n"
+            + "5Ndr9lNAansCXaUzXuVLp6dD6PnB8HVCE8tdETZrcXseyTBeltaxAhj+tCybJvDO\n"
+            + "sV8UmPR0w9ibExmUIVGX5BpoRlB/KWxEG3ar/wJbUZVZ2oSdIAZvCvdbN956SLDg\n"
+            + "Pg5M5wrRqs71s2EiIJd0HrU="
+    );
+    private final String keyType;
+    private final String trustedCert;
+    private final String endCert;
+    private final String privateKey;
+
+    private KeyType(String keyType, String selfCert, String privateKey) {
+        this.keyType = keyType;
+        this.trustedCert = selfCert;
+        this.endCert = selfCert;
+        this.privateKey = privateKey;
+    }
+
+    public String getKeyType() {
+        return keyType;
+    }
+
+    public String getTrustedCert() {
+        return trustedCert;
+    }
+
+    public String getEndCert() {
+        return endCert;
+    }
+
+    public String getPrivateKey() {
+        return privateKey;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/UnsupportedCiphersTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Testing that try to enable unsupported ciphers causes IllegalArgumentException.
+ */
+public class UnsupportedCiphersTest extends SSLEngineTestCase {
+
+    public static void main(String[] s) {
+        UnsupportedCiphersTest test = new UnsupportedCiphersTest();
+        test.runTests(Ciphers.UNSUPPORTED_CIPHERS);
+    }
+
+    @Override
+    protected void testOneCipher(String cipher) {
+        unsupTest(cipher, true);
+        unsupTest(cipher, false);
+    }
+
+    private void unsupTest(String cipher, boolean clientTest) {
+        SSLContext context = getContext();
+        SSLEngine clientEngine = context.createSSLEngine();
+        clientEngine.setUseClientMode(true);
+        SSLEngine serverEngine = context.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        if (clientTest) {
+            clientEngine.setEnabledCipherSuites(new String[]{cipher});
+        } else {
+            serverEngine.setEnabledCipherSuites(new String[]{cipher});
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSCommon/jaas.conf	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,17 @@
+com.sun.net.ssl.client {
+    com.sun.security.auth.module.Krb5LoginModule required
+    principal="USER@TEST.REALM"
+    doNotPrompt=true
+    useKeyTab=true
+    keyTab="krb5.keytab.data";
+};
+
+com.sun.net.ssl.server {
+    com.sun.security.auth.module.Krb5LoginModule required
+    principal="host/service.localhost@TEST.REALM"
+    isInitiator=false
+    useKeyTab=true
+    keyTab="krb5.keytab.data"
+    storeKey=true;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSDataExchangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS application data exchange using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSDataExchangeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm_sni TLSDataExchangeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=krb TLSDataExchangeTest
+ */
+
+/**
+ * Testing TLS application data exchange using each of the supported cipher
+ * suites.
+ */
+public class TLSDataExchangeTest {
+    public static void main(String[] args) {
+        DataExchangeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSEnginesClosureTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines closing using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm_sni TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=krb TLSEnginesClosureTest
+ */
+
+/**
+ * Testing TLS engines closing using each of the supported cipher suites.
+ */
+public class TLSEnginesClosureTest {
+    public static void main(String[] args) {
+        EnginesClosureTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSHandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines handshake using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSHandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm_sni TLSHandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=krb TLSHandshakeTest
+ */
+
+/**
+ * Testing TLS engines handshake using each of the supported cipher suites.
+ */
+public class TLSHandshakeTest {
+    public static void main(String[] args) {
+        HandshakeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSMFLNTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines handshake using each of the supported
+ *          cipher suites with different maximum fragment length. Testing of
+ *          MFLN extension.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=test TLSMFLNTest
+ */
+ // __run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm_sni TLSMFLNTest
+ // __run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=krb TLSMFLNTest
+
+/**
+ * Testing TLS engines handshake using each of the supported cipher suites with
+ * different maximum fragment length. Testing of MFLN extension.
+ */
+public class TLSMFLNTest {
+    public static void main(String[] args) {
+        MFLNTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSNotEnabledRC4Test.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines do not enable RC4 ciphers by default.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 TLSNotEnabledRC4Test
+ */
+
+/**
+ * Testing DTLS engines do not enable RC4 ciphers by default.
+ */
+public class TLSNotEnabledRC4Test {
+    public static void main(String[] args) throws Exception {
+        NotEnabledRC4Test.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSRehandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm_sni TLSRehandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=krb TLSRehandshakeTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking using each of the supported cipher
+ * suites.
+ */
+public class TLSRehandshakeTest {
+    public static void main(String[] args) {
+        RehandshakeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSRehandshakeWithCipherChangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2017, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking with cipher change. New cipher
+ *          is taken randomly from the supporetd ciphers list.
+ * @key randomness
+ * @library /sun/security/krb5/auto /test/lib /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @build jdk.test.lib.RandomFactory
+ * @run main/othervm -Dtest.security.protocol=TLSv1 TLSRehandshakeWithCipherChangeTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking with cipher change. New cipher is taken
+ * randomly from the supported ciphers list.
+ */
+public class TLSRehandshakeWithCipherChangeTest {
+    public static void main(String[] args) {
+        RehandshakeWithCipherChangeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSRehandshakeWithDataExTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking using each of the supported
+ *          cipher suites with application data exchange before and after
+ *          re-handshake and closing of the engines.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm TLSRehandshakeWithDataExTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=norm_sni TLSRehandshakeWithDataExTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1 -Dtest.mode=krb TLSRehandshakeWithDataExTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking using each of the supported cipher suites
+ * with application data exchange before and after re-handshake and closing of
+ * the engines.
+ */
+public class TLSRehandshakeWithDataExTest {
+    public static void main(String[] args) {
+        RehandshakeWithDataExTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv1/TLSUnsupportedCiphersTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing that try to enable unsupported ciphers
+ *          causes IllegalArgumentException.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1 TLSUnsupportedCiphersTest
+ */
+
+/**
+ * Testing that a try to enable unsupported ciphers causes IllegalArgumentException.
+ */
+public class TLSUnsupportedCiphersTest {
+    public static void main(String[] args) {
+        UnsupportedCiphersTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2010, 2016, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @run main/othervm ExportableBlockCipher
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @author Xuelei Fan
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+public class ExportableBlockCipher {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+        } catch (IOException ioe) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        // enable a exportable block cipher
+        sslSocket.setEnabledCipherSuites(
+            new String[] {"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        } catch (SSLException ssle) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ExportableBlockCipher();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ExportableBlockCipher() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2010, 2016, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4873188
+ * @summary Support TLS 1.1
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm ExportableStreamCipher
+ * @author Xuelei Fan
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+public class ExportableStreamCipher {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+        } catch (IOException ioe) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.1 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
+
+        // enable a exportable stream cipher
+        sslSocket.setEnabledCipherSuites(
+            new String[] {"SSL_RSA_EXPORT_WITH_RC4_40_MD5"});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        boolean interrupted = false;
+        try {
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        } catch (SSLException ssle) {
+            // get the expected exception
+            interrupted = true;
+        } finally {
+            sslSocket.close();
+        }
+
+        if (!interrupted) {
+            throw new SSLHandshakeException(
+                "A weak cipher suite is negotiated, " +
+                "TLSv1.1 must not negotiate the exportable cipher suites.");
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ExportableStreamCipher();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ExportableStreamCipher() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSDataExchangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS application data exchange using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSDataExchangeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm_sni TLSDataExchangeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=krb TLSDataExchangeTest
+ */
+
+/**
+ * Testing TLS application data exchange using each of the supported cipher
+ * suites.
+ */
+public class TLSDataExchangeTest {
+    public static void main(String[] args) {
+        DataExchangeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSEnginesClosureTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines closing using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm_sni TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=krb TLSEnginesClosureTest
+ */
+
+/**
+ * Testing TLS engines closing using each of the supported cipher suites.
+ */
+public class TLSEnginesClosureTest {
+    public static void main(String[] args) {
+        EnginesClosureTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSHandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines handshake using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSHandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm_sni TLSHandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=krb TLSHandshakeTest
+ */
+
+/**
+ * Testing TLS engines handshake using each of the supported cipher suites.
+ */
+public class TLSHandshakeTest {
+    public static void main(String[] args) {
+        HandshakeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSMFLNTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines handshake using each of the supported
+ *          cipher suites with different maximum fragment length. Testing of
+ *          MFLN extension.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSMFLNTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm_sni TLSMFLNTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=krb TLSMFLNTest
+ */
+
+/**
+ * Testing TLS engines handshake using each of the supported cipher suites with
+ * different maximum fragment length. Testing of MFLN extension.
+ */
+public class TLSMFLNTest {
+    public static void main(String[] args) {
+        MFLNTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSNotEnabledRC4Test.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines do not enable RC4 ciphers by default.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSNotEnabledRC4Test
+ */
+
+/**
+ * Testing DTLS engines do not enable RC4 ciphers by default.
+ */
+public class TLSNotEnabledRC4Test {
+    public static void main(String[] args) throws Exception {
+        NotEnabledRC4Test.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSRehandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm_sni TLSRehandshakeTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=krb TLSRehandshakeTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking using each of the supported cipher
+ * suites.
+ */
+public class TLSRehandshakeTest {
+    public static void main(String[] args) {
+        RehandshakeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSRehandshakeWithCipherChangeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2015, 2017, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking with cipher change. New cipher
+ *          is taken randomly from the supporetd ciphers list.
+ * @key randomness
+ * @library /sun/security/krb5/auto /test/lib /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @build jdk.test.lib.RandomFactory
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSRehandshakeWithCipherChangeTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking with cipher change. New cipher is taken
+ * randomly from the supported ciphers list.
+ */
+public class TLSRehandshakeWithCipherChangeTest {
+    public static void main(String[] args) {
+        RehandshakeWithCipherChangeTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSRehandshakeWithDataExTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing TLS engines re-handshaking using each of the supported
+ *          cipher suites with application data exchange before and after
+ *          re-handshake and closing of the engines.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm TLSRehandshakeWithDataExTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=norm_sni TLSRehandshakeWithDataExTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 -Dtest.mode=krb TLSRehandshakeWithDataExTest
+ */
+
+/**
+ * Testing TLS engines re-handshaking using each of the supported cipher suites
+ * with application data exchange before and after re-handshake and closing of
+ * the engines.
+ */
+public class TLSRehandshakeWithDataExTest {
+    public static void main(String[] args) {
+        RehandshakeWithDataExTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv11/TLSUnsupportedCiphersTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8085979
+ * @summary Testing that try to enable unsupported ciphers
+ *          causes IllegalArgumentException.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.1 TLSUnsupportedCiphersTest
+ */
+
+/**
+ * Testing that a try to enable unsupported ciphers causes IllegalArgumentException.
+ */
+public class TLSUnsupportedCiphersTest {
+    public static void main(String[] args) {
+        UnsupportedCiphersTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv12/DisabledShortDSAKeys.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8139565
+ * @summary Restrict certificates with DSA keys less than 1024 bits
+ *
+ * @run main/othervm DisabledShortDSAKeys PKIX TLSv1.2
+ * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1.2
+ * @run main/othervm DisabledShortDSAKeys PKIX TLSv1.1
+ * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1.1
+ * @run main/othervm DisabledShortDSAKeys PKIX TLSv1
+ * @run main/othervm DisabledShortDSAKeys SunX509 TLSv1
+ * @run main/othervm DisabledShortDSAKeys PKIX SSLv3
+ * @run main/othervm DisabledShortDSAKeys SunX509 SSLv3
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+
+public class DisabledShortDSAKeys {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDDjCCAs2gAwIBAgIJAO5/hbm1ByJOMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" +
+        "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzcwMTI2MDQz\n" +
+        "NTQ2WjAfMQswCQYDVQQGEwJVUzEQMA4GA1UEChMHRXhhbXBsZTCCAbgwggEsBgcq\n" +
+        "hkjOOAQBMIIBHwKBgQC4aSK8nBYdWJtuBkz6yoDyjZnNuGFSpDmx1ggKpLpcnPuw\n" +
+        "YKAbUhqdYhZtaIqQ4aO0T1ZS/HuOM0zvddnMUidFNX3RUvDkvdD/JYOnjqzCm+xW\n" +
+        "U0NFuPHZdapQY5KFk3ugkqZpHLY1StZbu0qugZOZjbBOMwB7cHAbMDuVpEr8DQIV\n" +
+        "AOi+ig+h3okFbWEE9MztiI2+DqNrAoGBAKh2EZbuWU9NoHglhVzfDUoz8CeyW6W6\n" +
+        "rUZuIOQsjWaYOeRPWX0UVAGq9ykIOfamEpurKt4H8ge/pHaL9iazJjonMHOXG12A\n" +
+        "0lALsMDGv22zVaJzXjOBvdPzc87opr0LIVgHASKOcDYjsICKNYPlS2cL3MJoD+bj\n" +
+        "NAR67b90VBbEA4GFAAKBgQCGrkRp2tdj2mZF7Qz0tO6p3xSysbEfN6QZxOJYPTvM\n" +
+        "yIYfLV9Yoy7XaRd/mCpJo/dqmsZMzowtyi+u+enuVpOLKiq/lyCktL+xUzZAjLT+\n" +
+        "9dafHlS1wR3pDSa1spo9xTEi4Ff/DQDHcdGalBxSXX/UdRtSecIYAp5/fkt3QZ5v\n" +
+        "0aOBkTCBjjAdBgNVHQ4EFgQUX4qbP5PgBx1J8BJ8qEgfoKVLSnQwTwYDVR0jBEgw\n" +
+        "RoAUX4qbP5PgBx1J8BJ8qEgfoKVLSnShI6QhMB8xCzAJBgNVBAYTAlVTMRAwDgYD\n" +
+        "VQQKEwdFeGFtcGxlggkA7n+FubUHIk4wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8E\n" +
+        "BAMCAgQwCQYHKoZIzjgEAwMwADAtAhUAkr5bINXyy/McAx6qwhb6r0/QJUgCFFUP\n" +
+        "CZokA4/NqJIgq8ThpTQAE8SB\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICUjCCAhGgAwIBAgIJAIiDrs/4W8rtMAkGByqGSM44BAMwHzELMAkGA1UEBhMC\n" +
+        "VVMxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMTYwMjE2MDQzNTQ2WhcNMzUxMTAzMDQz\n" +
+        "NTQ2WjA5MQswCQYDVQQGEwJVUzEQMA4GA1UECgwHRXhhbXBsZTEYMBYGA1UEAwwP\n" +
+        "d3d3LmV4YW1wbGUuY29tMIHwMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSv\n" +
+        "ThR/8GHpbL49KyWRJBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmp\n" +
+        "zYlUywIVAJLDcf4JXhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk\n" +
+        "5B8+ZHaHRi2KQ00ejilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14A0MA\n" +
+        "AkAYb+DYlFgStFhF1ip7rFzY8K6i/3ellkXI2umI/XVwxUQTHSlk5nFOep5Dfzm9\n" +
+        "pADJwuSe1qGHsHB5LpMZPVpto4GEMIGBMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgPo\n" +
+        "MB0GA1UdDgQWBBT8nsFyccF4q1dtpWE1dkNK5UiXtTAfBgNVHSMEGDAWgBRfips/\n" +
+        "k+AHHUnwEnyoSB+gpUtKdDAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
+        "CCsGAQUFBwMDMAkGByqGSM44BAMDMAAwLQIUIcIlxpIwaZXdpMC+U076unR1Mp8C\n" +
+        "FQCD/NE8O0xwq57nwFfp7tUvUHYMMA==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8, key size is 512 bits.
+    static String targetPrivateKey =
+        "MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEAs6A0p3TysTtVXGSvThR/8GHpbL49KyWR\n" +
+        "JBMIlmLc5jl/wxJgnL1t07p4YTOEa6ecyTFos04Z8n2GARmpzYlUywIVAJLDcf4J\n" +
+        "XhZbguRFSQdWwWhZkh+LAkBLCzh3Xvpmc/5CDqU+QHqDcuSk5B8+ZHaHRi2KQ00e\n" +
+        "jilpF2qZpW5JdHe4m3Pggh0MIuaAGX+leM4JKlnObj14BBYCFHB2Wek2g5hpNj5y\n" +
+        "RQfCc6CFO0dv";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(null, targetCertStr,
+                                            targetPrivateKey);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+            try (InputStream sslIS = sslSocket.getInputStream()) {
+                sslIS.read();
+            }
+
+            throw new Exception(
+                    "DSA keys shorter than 1024 bits should be disabled");
+        } catch (SSLHandshakeException sslhe) {
+            // the expected exception, ignore
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(trustedCertStr, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        try (SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort)) {
+
+            // only enable the target protocol
+            sslSocket.setEnabledProtocols(new String[] {enabledProtocol});
+
+            // enable a block cipher
+            sslSocket.setEnabledCipherSuites(
+                new String[] {"TLS_DHE_DSS_WITH_AES_128_CBC_SHA"});
+
+            try (OutputStream sslOS = sslSocket.getOutputStream()) {
+                sslOS.write('B');
+                sslOS.flush();
+            }
+
+            throw new Exception(
+                    "DSA keys shorter than 1024 bits should be disabled");
+        } catch (SSLHandshakeException sslhe) {
+            // the expected exception, ignore
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;        // trust manager
+    private static String enabledProtocol;    // the target protocol
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        enabledProtocol = args[1];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("DSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("DSA");
+            DSAPrivateKey priKey =
+                    (DSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = null;
+            if (trusedCert != null) {
+                chain = new Certificate[2];
+                chain[0] = keyCert;
+                chain[1] = trusedCert;
+            } else {
+                chain = new Certificate[1];
+                chain[0] = keyCert;
+            }
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "DSA keySize < 1024");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "DSA keySize < 1024");
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new DisabledShortDSAKeys();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    DisabledShortDSAKeys() throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv12/DisabledShortRSAKeys.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2012, 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7109274
+ * @summary Consider disabling support for X.509 certificates with RSA keys
+ *          less than 1024 bits
+ * @library /javax/net/ssl/templates
+ * @run main/othervm DisabledShortRSAKeys PKIX TLSv1.2
+ * @run main/othervm DisabledShortRSAKeys SunX509 TLSv1.2
+ * @run main/othervm DisabledShortRSAKeys PKIX TLSv1.1
+ * @run main/othervm DisabledShortRSAKeys SunX509 TLSv1.1
+ * @run main/othervm DisabledShortRSAKeys PKIX TLSv1
+ * @run main/othervm DisabledShortRSAKeys SunX509 TLSv1
+ * @run main/othervm DisabledShortRSAKeys PKIX SSLv3
+ * @run main/othervm DisabledShortRSAKeys SunX509 SSLv3
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+
+public class DisabledShortRSAKeys extends SSLSocketTemplate {
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" +
+        "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" +
+        "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" +
+        "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" +
+        "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
+        "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" +
+        "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" +
+        "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+        "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" +
+        "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" +
+        "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" +
+        "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" +
+        "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" +
+        "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" +
+        "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" +
+        "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8, key size is 512 bits.
+    static String targetPrivateKey =
+        "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" +
+        "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" +
+        "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" +
+        "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" +
+        "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" +
+        "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" +
+        "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" +
+        "3fnqsTgaUs4=";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    @Override
+    protected SSLContext createClientSSLContext() throws Exception {
+        return generateSSLContext(trustedCertStr, null, null);
+    }
+
+    @Override
+    protected SSLContext createServerSSLContext() throws Exception {
+        return generateSSLContext(null, targetCertStr, targetPrivateKey);
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        try {
+            try (InputStream sslIS = socket.getInputStream()) {
+                sslIS.read();
+            }
+            throw new Exception("RSA keys shorter than 1024 bits should be disabled");
+        } catch (SSLHandshakeException sslhe) {
+            // the expected exception, ignore
+        }
+
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+
+        try {
+
+            // only enable the target protocol
+            socket.setEnabledProtocols(new String[] { enabledProtocol });
+            // enable a block cipher
+            socket.setEnabledCipherSuites(
+                new String[] { "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" });
+
+            try (OutputStream sslOS = socket.getOutputStream()) {
+                sslOS.write('B');
+                sslOS.flush();
+            }
+            throw new Exception(
+               "RSA keys shorter than 1024 bits should be disabled");
+        } catch (SSLHandshakeException sslhe) {
+            // the expected exception, ignore
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm; // trust manager
+    private static String enabledProtocol; // the target protocol
+
+    private static void parseArguments(String[] args) {
+            tmAlgorithm = args[0];
+            enabledProtocol = args[1];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+                String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("RSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                            Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = null;
+            if (trusedCert != null) {
+                chain = new Certificate[2];
+                chain[0] = keyCert;
+                chain[1] = trusedCert;
+            } else {
+                chain = new Certificate[1];
+                chain[0] = keyCert;
+            }
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "RSA keySize < 1024");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "RSA keySize < 1024");
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new DisabledShortRSAKeys().run();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv12/ShortRSAKey512.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2012, 2016, 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.
+ */
+
+// This test case relies on updated static security property, no way to re-use
+// security property in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7106773
+ * @summary 512 bits RSA key cannot work with SHA384 and SHA512
+ *
+ *     SunJSSE does not support dynamic system properties, no way to re-use
+ *     system properties in samevm/agentvm mode.
+ * @run main/othervm ShortRSAKey512 PKIX
+ * @run main/othervm ShortRSAKey512 SunX509
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+
+public class ShortRSAKey512 {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" +
+        "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" +
+        "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" +
+        "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" +
+        "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
+        "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" +
+        "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" +
+        "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+        "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" +
+        "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" +
+        "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" +
+        "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" +
+        "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" +
+        "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" +
+        "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" +
+        "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8, key size is 512 bits.
+    static String targetPrivateKey =
+        "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" +
+        "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" +
+        "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" +
+        "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" +
+        "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" +
+        "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" +
+        "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" +
+        "3fnqsTgaUs4=";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = true;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(null, targetCertStr,
+                                            targetPrivateKey);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        try (SSLServerSocket sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(serverPort)) {
+
+            serverPort = sslServerSocket.getLocalPort();
+            System.out.println("Start server on port " + serverPort);
+
+            /*
+            * Signal Client, we're ready for his connect.
+            */
+            serverReady = true;
+
+            try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+
+                sslIS.read();
+                sslOS.write('A');
+                sslOS.flush();
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(trustedCertStr, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        System.out.println("Client connects to port " + serverPort);
+        try (SSLSocket sslSocket =
+                (SSLSocket) sslsf.createSocket("localhost", serverPort)) {
+
+            // enable TLSv1.2 only
+            sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
+
+            // enable a block cipher
+            sslSocket.setEnabledCipherSuites(
+                new String[] {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA"});
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;        // trust manager
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("RSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = null;
+            if (trusedCert != null) {
+                chain = new Certificate[2];
+                chain[0] = keyCert;
+                chain[1] = trusedCert;
+            } else {
+                chain = new Certificate[1];
+                chain[0] = keyCert;
+            }
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new ShortRSAKey512();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ShortRSAKey512() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        e.printStackTrace(System.err);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.setDaemon(true);
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        e.printStackTrace(System.err);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.setDaemon(true);
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv12/ShortRSAKeyGCM.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,446 @@
+/*
+ * 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
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7030966
+ * @summary Support AEAD CipherSuites
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_128_GCM_SHA256
+ */
+
+/*
+ * Need additional key materials to run the following cases.
+ *
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ *
+ * Need unlimited JCE Unlimited Strength Jurisdiction Policy to run the
+ * following cases.
+ *
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_RSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ * @run main/othervm ShortRSAKeyGCM PKIX TLS_DH_anon_WITH_AES_256_GCM_SHA384
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+
+
+public class ShortRSAKeyGCM {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTEwODE5MDE1MjE5WhcNMzIwNzI5MDE1MjE5WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBAM8orG08DtF98TMSscjGsidd1ZoN4jiDpi8U\n" +
+        "ICz+9dMm1qM1d7O2T+KH3/mxyox7Rc2ZVSCaUD0a3CkhPMnlAx8V4u0H+E9sqso6\n" +
+        "iDW3JpOyzMExvZiRgRG/3nvp55RMIUV4vEHOZ1QbhuqG4ebN0Vz2DkRft7+flthf\n" +
+        "vDld6f5JAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLl81dnfp0wDrv0OJ1sxlWzH83Xh\n" +
+        "MGMGA1UdIwRcMFqAFLl81dnfp0wDrv0OJ1sxlWzH83XhoT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEE\n" +
+        "BQADgYEALlgaH1gWtoBZ84EW8Hu6YtGLQ/L9zIFmHonUPZwn3Pr//icR9Sqhc3/l\n" +
+        "pVTxOINuFHLRz4BBtEylzRIOPzK3tg8XwuLb1zd0db90x3KBCiAL6E6cklGEPwLe\n" +
+        "XYMHDn9eDsaq861Tzn6ZwzMgw04zotPMoZN0mVd/3Qca8UJFucE=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICNDCCAZ2gAwIBAgIBDDANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTExMTA3MTM1NTUyWhcNMzEwNzI1MTM1NTUyWjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+        "BAMTCWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQC3Pb49OSPfOD2G\n" +
+        "HSXFCFx1GJEZfqG9ZUf7xuIi/ra5dLjPGAaoY5QF2QOa8VnOriQCXDfyXHxsuRnE\n" +
+        "OomxL7EVAgMBAAGjeDB2MAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQUXNCJK3/dtCIc\n" +
+        "xb+zlA/JINlvs/MwHwYDVR0jBBgwFoAUuXzV2d+nTAOu/Q4nWzGVbMfzdeEwJwYD\n" +
+        "VR0lBCAwHgYIKwYBBQUHAwEGCCsGAQUFBwMCBggrBgEFBQcDAzANBgkqhkiG9w0B\n" +
+        "AQQFAAOBgQB2qIDUxA2caMPpGtUACZAPRUtrGssCINIfItETXJZCx/cRuZ5sP4D9\n" +
+        "N1acoNDn0hCULe3lhXAeTC9NZ97680yJzregQMV5wATjo1FGsKY30Ma+sc/nfzQW\n" +
+        "+h/7RhYtoG0OTsiaDCvyhI6swkNJzSzrAccPY4+ZgU8HiDLzZTmM3Q==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8, key size is 512 bits.
+    static String targetPrivateKey =
+        "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAtz2+PTkj3zg9hh0l\n" +
+        "xQhcdRiRGX6hvWVH+8biIv62uXS4zxgGqGOUBdkDmvFZzq4kAlw38lx8bLkZxDqJ\n" +
+        "sS+xFQIDAQABAkByx/5Oo2hQ/w2q4L8z+NTRlJ3vdl8iIDtC/4XPnfYfnGptnpG6\n" +
+        "ZThQRvbMZiai0xHQPQMszvAHjZVme1eDl3EBAiEA3aKJHynPVCEJhpfCLWuMwX5J\n" +
+        "1LntwJO7NTOyU5m8rPECIQDTpzn5X44r2rzWBDna/Sx7HW9IWCxNgUD2Eyi2nA7W\n" +
+        "ZQIgJerEorw4aCAuzQPxiGu57PB6GRamAihEAtoRTBQlH0ECIQDN08FgTtnesgCU\n" +
+        "DFYLLcw1CiHvc7fZw4neBDHCrC8NtQIgA8TOUkGnpCZlQ0KaI8KfKWI+vxFcgFnH\n" +
+        "3fnqsTgaUs4=";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(null, targetCertStr,
+                                            targetPrivateKey);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+        sslSocket.setEnabledCipherSuites(sslSocket.getSupportedCipherSuites());
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write('A');
+        sslOS.flush();
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(trustedCertStr, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+        // enable TLSv1.2 only
+        sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
+
+        // enable a block cipher
+        sslSocket.setEnabledCipherSuites(new String[] {cipherSuite});
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write('B');
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;        // trust manager
+    private static String cipherSuite;        // cipher suite
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        cipherSuite = args[1];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("RSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = null;
+            if (trusedCert != null) {
+                chain = new Certificate[2];
+                chain[0] = keyCert;
+                chain[1] = trusedCert;
+            } else {
+                chain = new Certificate[1];
+                chain[0] = keyCert;
+            }
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "MD2");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new ShortRSAKeyGCM();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ShortRSAKeyGCM() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died..." + e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died..." + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv12/SignatureAlgorithms.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,592 @@
+/*
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8049321
+ * @summary Support SHA256WithDSA in JSSE
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-224,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-224"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-224,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-224"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ * @run main/othervm SignatureAlgorithms PKIX "SHA-1,SHA-256"
+ *                   TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+
+public class SignatureAlgorithms {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key (DSA) used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDYTCCAyGgAwIBAgIJAK8/gw6zg/DPMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" +
+        "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" +
+        "MB4XDTE1MTIwMzEzNTIyNVoXDTM2MTExMjEzNTIyNVowOzELMAkGA1UEBhMCVVMx\n" +
+        "DTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNlMIIB\n" +
+        "uDCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG4X+uxu5V\n" +
+        "b3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2eBfUv/hJ\n" +
+        "cLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNAqAB9PO5Y\n" +
+        "zKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAaor8iURd82\n" +
+        "b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I81drnN0Y\n" +
+        "lyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVXW+SEGADC\n" +
+        "J1+z8uqP3lIB6ltdgOiV/GQDgYUAAoGBAOXRppuJSGdt6AiZkb81P1DCUgIUlZFI\n" +
+        "J9GxWrjbbHDmGllMwPNhK6dU7LJKJJuYVPW+95rUGlSJEjRqSlHuyHkNb6e3e7qx\n" +
+        "tmx1/oIyq+oLult50hBS7uBvLLR0JbIKjBzzkudL8Rjze4G/Wq7KDM2T1JOP49tW\n" +
+        "eocCvaC8h8uQo4GtMIGqMB0GA1UdDgQWBBT17HcqLllsqnZzP+kElcGcBGmubjBr\n" +
+        "BgNVHSMEZDBigBT17HcqLllsqnZzP+kElcGcBGmubqE/pD0wOzELMAkGA1UEBhMC\n" +
+        "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" +
+        "ggkArz+DDrOD8M8wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwCQYHKoZI\n" +
+        "zjgEAwMvADAsAhQ6Y1I6LtIEBMqNo8o6GIe4LLEJuwIUbVQUKi8tvtWyRoxm8AFV\n" +
+        "0axJYUU=\n" +
+        "-----END CERTIFICATE-----";
+
+    static String[] targetCertStr = {
+        // DSA-SHA1
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDKTCCAumgAwIBAgIJAOy5c0b+8stFMAkGByqGSM44BAMwOzELMAkGA1UEBhMC\n" +
+        "VVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNl\n" +
+        "MB4XDTE1MTIwMzEzNTIyNVoXDTM1MDgyMDEzNTIyNVowTzELMAkGA1UEBhMCVVMx\n" +
+        "DTALBgNVBAoMBEphdmExHTAbBgNVBAsMFFN1bkpTU0UgVGVzdCBTZXJpdmNlMRIw\n" +
+        "EAYDVQQDDAlsb2NhbGhvc3QwggG3MIIBLAYHKoZIzjgEATCCAR8CgYEA8f5v4ZIx\n" +
+        "fopLuNcNF6/NzjrgMUbhf67G7lVvdTjKGxTwDxy4fiDCKfov8gOSZlDs3TMLSNGy\n" +
+        "IZVIywURNOrXQXf2kfZ4F9S/+Elwt8GciMES1WpX90TErzwe6XaxniZCKFDiKyw+\n" +
+        "XuGyuhL0RZiJydfSg0CoAH087ljMpt+kvtMCFQDXdZbjyuWfZQ/8toCC2fMqGpw2\n" +
+        "0wKBgQDdG/QaKtNsBqivyJRF3zZvkWUNN684JO6rtkil9lVXfSd5LtwFg163qb/f\n" +
+        "/hx9SVtuuqFuognYj4jzV2uc3RiXI3gqS7ERwHo5PB9aQhSPqu89oJCsEfxDbXds\n" +
+        "Orcce1g1o/w6h5BTJVdb5IQYAMInX7Py6o/eUgHqW12A6JX8ZAOBhAACgYB+zYqn\n" +
+        "jJwG4GZpBIN/6qhzbp0flChsV+Trlu0SL0agAQzb6XdI/4JnO87Pgbxaxh3VNAj3\n" +
+        "3+Ghr1NLBuBfTKzJ4j9msWT3EpLupkMyNtXvBYM0iyMrll67lSjMdv++wLEw35Af\n" +
+        "/bzVcjGyA5Q0i0cuEzDmHTVfi0OydynbwSLxtKNjMGEwCwYDVR0PBAQDAgPoMB0G\n" +
+        "A1UdDgQWBBQXJI8AxM0qsYCbbkIMuI5zJ+nMEDAfBgNVHSMEGDAWgBT17HcqLlls\n" +
+        "qnZzP+kElcGcBGmubjASBgNVHREBAf8ECDAGhwR/AAABMAkGByqGSM44BAMDLwAw\n" +
+        "LAIUXgyJ0xll4FrZAKXi8bj7Kiz+SA4CFH9WCSZIBYA9lmJkiTgRS7iM/6IC\n" +
+        "-----END CERTIFICATE-----",
+
+        // DSA-SHA224
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDLzCCAuugAwIBAgIJAOy5c0b+8stGMAsGCWCGSAFlAwQDATA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTUxMjAzMTU0NDM5WhcNMzUwODIwMTU0NDM5WjBPMQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+        "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" +
+        "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" +
+        "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" +
+        "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" +
+        "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" +
+        "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" +
+        "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgA81\n" +
+        "CJKEv+pwiqYgxtw/9rkQ9748WP3mKrEC06kjUG+94/Z9dQloNFFfj6LiO1bymc5l\n" +
+        "6QIR8XCi4Po3N80K3+WxhBGFhY+RkVWTh43JV8epb41aH2qiWErarBwBGEh8LyGT\n" +
+        "i30db+Nkz2gfvyz9H/9T0jmYgfLEOlMCusali1qHo2MwYTALBgNVHQ8EBAMCA+gw\n" +
+        "HQYDVR0OBBYEFBqSP0S4+X+zOCTEnlp2hbAjV/W5MB8GA1UdIwQYMBaAFPXsdyou\n" +
+        "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMB\n" +
+        "AzEAMC4CFQChiRaOnAnsCSJFwdpK22jSxU/mhQIVALgLbj/G39+1Ej8UuSWnEQyU\n" +
+        "4DA+\n" +
+        "-----END CERTIFICATE-----",
+
+        // DSA-SHA256
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDLTCCAuugAwIBAgIJAOy5c0b+8stHMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTUxMjAzMTU0NjUxWhcNMzUwODIwMTU0NjUxWjBPMQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+        "EjAQBgNVBAMMCWxvY2FsaG9zdDCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQDx/m/h\n" +
+        "kjF+iku41w0Xr83OOuAxRuF/rsbuVW91OMobFPAPHLh+IMIp+i/yA5JmUOzdMwtI\n" +
+        "0bIhlUjLBRE06tdBd/aR9ngX1L/4SXC3wZyIwRLValf3RMSvPB7pdrGeJkIoUOIr\n" +
+        "LD5e4bK6EvRFmInJ19KDQKgAfTzuWMym36S+0wIVANd1luPK5Z9lD/y2gILZ8yoa\n" +
+        "nDbTAoGBAN0b9Boq02wGqK/IlEXfNm+RZQ03rzgk7qu2SKX2VVd9J3ku3AWDXrep\n" +
+        "v9/+HH1JW266oW6iCdiPiPNXa5zdGJcjeCpLsRHAejk8H1pCFI+q7z2gkKwR/ENt\n" +
+        "d2w6txx7WDWj/DqHkFMlV1vkhBgAwidfs/Lqj95SAepbXYDolfxkA4GEAAKBgEF7\n" +
+        "2qiYxGrjX4KCOy0k5nK/RYlgLy4gYDChihQpiaa+fbA5JOBOxPWsh7rdtmJuDrEJ\n" +
+        "keacU223+DIhOKC49fa+EvhLNqo6U1oPn8n/yvBsvvnWkcynw5KfNzaLlaPmzugh\n" +
+        "v9xl/GhyZNAXc1QUcW3C+ceHVNrKnkfbTKZz5eRSo2MwYTALBgNVHQ8EBAMCA+gw\n" +
+        "HQYDVR0OBBYEFNMkPrt40oO9Dpy+bcbQdEvOlNlyMB8GA1UdIwQYMBaAFPXsdyou\n" +
+        "WWyqdnM/6QSVwZwEaa5uMBIGA1UdEQEB/wQIMAaHBH8AAAEwCwYJYIZIAWUDBAMC\n" +
+        "Ay8AMCwCFCvA2QiKSe/n+6GqSYQwgQ/zL5M9AhQfSiuWdMJKWpgPJKakvzhBUbMb\n" +
+        "vA==\n" +
+        "-----END CERTIFICATE-----"};
+
+    // Private key in the format of PKCS#8, key size is 1024 bits.
+    static String[] targetPrivateKey = {
+        // For cert DSA-SHA1
+        "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" +
+        "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" +
+        "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" +
+        "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" +
+        "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" +
+        "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" +
+        "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOiB7J/lrFrNduQ8nDNTe8VspoAI=",
+
+        // For cert DSA-SHA224
+        "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" +
+        "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" +
+        "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" +
+        "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" +
+        "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" +
+        "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" +
+        "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUOj9F5mxWd9W1tiLSdsOAt8BUBzE=",
+
+        // For cert DSA-SHA256
+        "MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAPH+b+GSMX6KS7jXDRevzc464DFG\n" +
+        "4X+uxu5Vb3U4yhsU8A8cuH4gwin6L/IDkmZQ7N0zC0jRsiGVSMsFETTq10F39pH2\n" +
+        "eBfUv/hJcLfBnIjBEtVqV/dExK88Hul2sZ4mQihQ4issPl7hsroS9EWYicnX0oNA\n" +
+        "qAB9PO5YzKbfpL7TAhUA13WW48rln2UP/LaAgtnzKhqcNtMCgYEA3Rv0GirTbAao\n" +
+        "r8iURd82b5FlDTevOCTuq7ZIpfZVV30neS7cBYNet6m/3/4cfUlbbrqhbqIJ2I+I\n" +
+        "81drnN0YlyN4KkuxEcB6OTwfWkIUj6rvPaCQrBH8Q213bDq3HHtYNaP8OoeQUyVX\n" +
+        "W+SEGADCJ1+z8uqP3lIB6ltdgOiV/GQEFgIUQ2WGgg+OO39Aujj0e4lM4pP4/9g="};
+
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile boolean serverReady = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+
+        SSLContext context = generateSSLContext(
+                null, targetCertStr, targetPrivateKey);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        try (SSLServerSocket sslServerSocket =
+                (SSLServerSocket)sslssf.createServerSocket(serverPort)) {
+
+            serverPort = sslServerSocket.getLocalPort();
+
+            /*
+             * Signal Client, we're ready for his connect.
+             */
+            serverReady = true;
+
+            try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+                sslSocket.setEnabledCipherSuites(
+                        sslSocket.getSupportedCipherSuites());
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+
+                sslIS.read();
+                sslOS.write('A');
+                sslOS.flush();
+
+                dumpSignatureAlgorithms(sslSocket);
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(trustedCertStr, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        try (SSLSocket sslSocket =
+                (SSLSocket)sslsf.createSocket("localhost", serverPort)) {
+
+            // enable TLSv1.2 only
+            sslSocket.setEnabledProtocols(new String[] {"TLSv1.2"});
+
+            // enable a block cipher
+            sslSocket.setEnabledCipherSuites(new String[] {cipherSuite});
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+
+            dumpSignatureAlgorithms(sslSocket);
+        }
+    }
+
+    static void dumpSignatureAlgorithms(SSLSocket sslSocket) throws Exception {
+
+        boolean isClient = sslSocket.getUseClientMode();
+        String mode = "[" + (isClient ? "Client" : "Server") + "]";
+        ExtendedSSLSession session =
+                (ExtendedSSLSession)sslSocket.getSession();
+        String[] signAlgs = session.getLocalSupportedSignatureAlgorithms();
+        System.out.println(
+                mode + " local supported signature algorithms: " +
+                Arrays.asList(signAlgs));
+
+        if (!isClient) {
+            signAlgs = session.getPeerSupportedSignatureAlgorithms();
+            System.out.println(
+                mode + " peer supported signature algorithms: " +
+                Arrays.asList(signAlgs));
+        } else {
+            Certificate[] serverCerts = session.getPeerCertificates();
+
+            // server should always send the authentication cert.
+            String sigAlg = ((X509Certificate)serverCerts[0]).getSigAlgName();
+            System.out.println(
+                mode + " the signature algorithm of server certificate: " +
+                sigAlg);
+            if (sigAlg.contains("SHA1")) {
+                if (disabledAlgorithms.contains("SHA-1")) {
+                    throw new Exception(
+                            "Not the expected server certificate. " +
+                            "SHA-1 should be disabled");
+                }
+            } else if (sigAlg.contains("SHA224")) {
+                if (disabledAlgorithms.contains("SHA-224")) {
+                    throw new Exception(
+                            "Not the expected server certificate. " +
+                            "SHA-224 should be disabled");
+                }
+            } else {    // SHA-256
+                if (disabledAlgorithms.contains("SHA-256")) {
+                    throw new Exception(
+                            "Not the expected server certificate. " +
+                            "SHA-256 should be disabled");
+                }
+            }
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;          // trust manager
+    private static String disabledAlgorithms;   // disabled algorithms
+    private static String cipherSuite;          // cipher suite
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        disabledAlgorithms = args[1];
+        cipherSuite = args[2];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String[] keyCertStrs, String[] keySpecStrs) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("DSA Signer", trusedCert);
+        }
+
+        if (keyCertStrs != null && keyCertStrs.length != 0) {
+            for (int i = 0; i < keyCertStrs.length; i++) {
+                String keyCertStr = keyCertStrs[i];
+                String keySpecStr = keySpecStrs[i];
+
+                // generate the private key.
+                PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+                KeyFactory kf = KeyFactory.getInstance("DSA");
+                DSAPrivateKey priKey =
+                        (DSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+                // generate certificate chain
+                is = new ByteArrayInputStream(keyCertStr.getBytes());
+                Certificate keyCert = cf.generateCertificate(is);
+                is.close();
+
+                Certificate[] chain = null;
+                if (trusedCert != null) {
+                    chain = new Certificate[2];
+                    chain[0] = keyCert;
+                    chain[1] = trusedCert;
+                } else {
+                    chain = new Certificate[1];
+                    chain[0] = keyCert;
+                }
+
+                // import the key entry.
+                ks.setKeyEntry("DSA Entry " + i, priKey, passphrase, chain);
+            }
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStrs != null && keyCertStrs.length != 0) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        /*
+         * debug option
+         */
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+
+        /*
+         * Ignore testing on Windows if only SHA-224 is available.
+         */
+        if ((Security.getProvider("SunMSCAPI") != null) &&
+                (disabledAlgorithms.contains("SHA-1")) &&
+                (disabledAlgorithms.contains("SHA-256"))) {
+
+            System.out.println(
+                "Windows system does not support SHA-224 algorithms yet. " +
+                "Ignore the testing");
+
+            return;
+        }
+
+        /*
+         * Expose the target algorithms by diabling unexpected algorithms.
+         */
+        Security.setProperty(
+                "jdk.certpath.disabledAlgorithms", disabledAlgorithms);
+
+        /*
+         * Reset the security property to make sure that the algorithms
+         * and keys used in this test are not disabled by default.
+         */
+        Security.setProperty( "jdk.tls.disabledAlgorithms", "");
+
+        /*
+         * Start the tests.
+         */
+        new SignatureAlgorithms();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SignatureAlgorithms() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died..." + e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died..." + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/TLSv12/TLSEnginesClosureTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8207009
+ * @summary Testing TLS engines closing using each of the supported
+ *          cipher suites.
+ * @library /sun/security/krb5/auto /javax/net/ssl/TLSCommon
+ * @modules java.security.jgss
+ *          jdk.security.auth
+ *          java.security.jgss/sun.security.jgss.krb5
+ *          java.security.jgss/sun.security.krb5:+open
+ *          java.security.jgss/sun.security.krb5.internal:+open
+ *          java.security.jgss/sun.security.krb5.internal.ccache
+ *          java.security.jgss/sun.security.krb5.internal.crypto
+ *          java.security.jgss/sun.security.krb5.internal.ktab
+ *          java.base/sun.security.util
+ * @run main/othervm -Dtest.security.protocol=TLSv1.2
+ *     -Dtest.mode=norm TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.2
+ *     -Dtest.mode=norm_sni TLSEnginesClosureTest
+ * @run main/othervm -Dtest.security.protocol=TLSv1.2
+ *     -Dtest.mode=krb TLSEnginesClosureTest
+ */
+
+/**
+ * Testing TLS engines closing using each of the supported cipher suites.
+ */
+public class TLSEnginesClosureTest {
+    public static void main(String[] args) {
+        EnginesClosureTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ciphersuites/DisabledAlgorithms.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2015, 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8076221 8211883
+ * @summary Check if weak cipher suites are disabled
+ * @modules jdk.crypto.ec
+ * @run main/othervm DisabledAlgorithms default
+ * @run main/othervm DisabledAlgorithms empty
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.util.concurrent.TimeUnit;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+public class DisabledAlgorithms {
+
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    private static final String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+
+    private static final String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    // supported RC4, NULL, and anon cipher suites
+    // it does not contain KRB5 cipher suites because they need a KDC
+    private static final String[] rc4_null_anon_ciphersuites = new String[] {
+        "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
+        "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+        "SSL_RSA_WITH_RC4_128_SHA",
+        "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
+        "TLS_ECDH_RSA_WITH_RC4_128_SHA",
+        "SSL_RSA_WITH_RC4_128_MD5",
+        "TLS_ECDH_anon_WITH_RC4_128_SHA",
+        "SSL_DH_anon_WITH_RC4_128_MD5",
+        "SSL_RSA_WITH_NULL_MD5",
+        "SSL_RSA_WITH_NULL_SHA",
+        "TLS_RSA_WITH_NULL_SHA256",
+        "TLS_ECDH_ECDSA_WITH_NULL_SHA",
+        "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
+        "TLS_ECDH_RSA_WITH_NULL_SHA",
+        "TLS_ECDHE_RSA_WITH_NULL_SHA",
+        "TLS_ECDH_anon_WITH_NULL_SHA",
+        "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+        "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+        "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+        "SSL_DH_anon_WITH_DES_CBC_SHA",
+        "SSL_DH_anon_WITH_RC4_128_MD5",
+        "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+        "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
+        "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
+        "TLS_DH_anon_WITH_AES_256_CBC_SHA",
+        "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
+        "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
+        "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_anon_WITH_NULL_SHA",
+        "TLS_ECDH_anon_WITH_RC4_128_SHA"
+    };
+
+    public static void main(String[] args) throws Exception {
+        if (args.length < 1) {
+            throw new RuntimeException("No parameters specified");
+        }
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        switch (args[0]) {
+            case "default":
+                // use default jdk.tls.disabledAlgorithms
+                System.out.println("jdk.tls.disabledAlgorithms = "
+                        + Security.getProperty("jdk.tls.disabledAlgorithms"));
+
+                // check if RC4, NULL, and anon cipher suites
+                // can't be used by default
+                checkFailure(rc4_null_anon_ciphersuites);
+                break;
+            case "empty":
+                // reset jdk.tls.disabledAlgorithms
+                Security.setProperty("jdk.tls.disabledAlgorithms", "");
+                System.out.println("jdk.tls.disabledAlgorithms = "
+                        + Security.getProperty("jdk.tls.disabledAlgorithms"));
+
+                // check if RC4, NULL, and anon cipher suites can be used
+                // if jdk.tls.disabledAlgorithms is empty
+                checkSuccess(rc4_null_anon_ciphersuites);
+                break;
+            default:
+                throw new RuntimeException("Wrong parameter: " + args[0]);
+        }
+
+        System.out.println("Test passed");
+    }
+
+    /*
+     * Checks if that specified cipher suites cannot be used.
+     */
+    private static void checkFailure(String[] ciphersuites) throws Exception {
+        try (SSLServer server = SSLServer.init(ciphersuites)) {
+            startNewThread(server);
+            while (!server.isRunning()) {
+                sleep();
+            }
+
+            int port = server.getPort();
+            for (String ciphersuite : ciphersuites) {
+                try (SSLClient client = SSLClient.init(port, ciphersuite)) {
+                    client.connect();
+                    throw new RuntimeException("Expected SSLHandshakeException "
+                            + "not thrown");
+                } catch (SSLHandshakeException e) {
+                    System.out.println("Expected exception on client side: "
+                            + e);
+                }
+            }
+
+            while (server.isRunning()) {
+                sleep();
+            }
+
+            if (!server.sslError()) {
+                throw new RuntimeException("Expected SSL exception "
+                        + "not thrown on server side");
+            }
+        }
+
+    }
+
+    /*
+     * Checks if specified cipher suites can be used.
+     */
+    private static void checkSuccess(String[] ciphersuites) throws Exception {
+        try (SSLServer server = SSLServer.init(ciphersuites)) {
+            startNewThread(server);
+            while (!server.isRunning()) {
+                sleep();
+            }
+
+            int port = server.getPort();
+            for (String ciphersuite : ciphersuites) {
+                try (SSLClient client = SSLClient.init(port, ciphersuite)) {
+                    client.connect();
+                    String negotiated = client.getNegotiatedCipherSuite();
+                    System.out.println("Negotiated cipher suite: "
+                            + negotiated);
+                    if (!negotiated.equals(ciphersuite)) {
+                        throw new RuntimeException("Unexpected cipher suite: "
+                                + negotiated);
+                    }
+                }
+            }
+
+            server.stop();
+            while (server.isRunning()) {
+                sleep();
+            }
+
+            if (server.error()) {
+                throw new RuntimeException("Unexpected error on server side");
+            }
+        }
+
+    }
+
+    private static Thread startNewThread(SSLServer server) {
+        Thread serverThread = new Thread(server, "SSL server thread");
+        serverThread.setDaemon(true);
+        serverThread.start();
+        return serverThread;
+    }
+
+    private static void sleep() {
+        try {
+            TimeUnit.MILLISECONDS.sleep(50);
+        } catch (InterruptedException e) {
+            // do nothing
+        }
+    }
+
+    static class SSLServer implements Runnable, AutoCloseable {
+
+        private final SSLServerSocket ssocket;
+        private volatile boolean stopped = false;
+        private volatile boolean running = false;
+        private volatile boolean sslError = false;
+        private volatile boolean otherError = false;
+
+        private SSLServer(SSLServerSocket ssocket) {
+            this.ssocket = ssocket;
+        }
+
+        @Override
+        public void run() {
+            System.out.println("Server: started");
+            running = true;
+            while (!stopped) {
+                try (SSLSocket socket = (SSLSocket) ssocket.accept()) {
+                    System.out.println("Server: accepted client connection");
+                    InputStream in = socket.getInputStream();
+                    OutputStream out = socket.getOutputStream();
+                    int b = in.read();
+                    if (b < 0) {
+                        throw new IOException("Unexpected EOF");
+                    }
+                    System.out.println("Server: send data: " + b);
+                    out.write(b);
+                    out.flush();
+                    socket.getSession().invalidate();
+                } catch (SSLHandshakeException e) {
+                    System.out.println("Server: run: " + e);
+                    sslError = true;
+                    stopped = true;
+                } catch (IOException e) {
+                    if (!stopped) {
+                        System.out.println("Server: run: unexpected exception: "
+                                + e);
+                        e.printStackTrace();
+                        otherError = true;
+                        stopped = true;
+                    } else {
+                        System.out.println("Server: run: " + e);
+                        System.out.println("The exception above occurred "
+                                    + "because socket was closed, "
+                                    + "please ignore it");
+                    }
+                }
+            }
+
+            System.out.println("Server: finished");
+            running = false;
+        }
+
+        int getPort() {
+            return ssocket.getLocalPort();
+        }
+
+        String[] getEnabledCiperSuites() {
+            return ssocket.getEnabledCipherSuites();
+        }
+
+        boolean isRunning() {
+            return running;
+        }
+
+        boolean sslError() {
+            return sslError;
+        }
+
+        boolean error() {
+            return sslError || otherError;
+        }
+
+        void stop() {
+            stopped = true;
+            if (!ssocket.isClosed()) {
+                try {
+                    System.out.println("Server: close socket");
+                    ssocket.close();
+                } catch (IOException e) {
+                    System.out.println("Server: close: " + e);
+                }
+            }
+        }
+
+        @Override
+        public void close() {
+            stop();
+        }
+
+        static SSLServer init(String[] ciphersuites)
+                throws IOException {
+            SSLServerSocketFactory ssf = (SSLServerSocketFactory)
+                    SSLServerSocketFactory.getDefault();
+            SSLServerSocket ssocket = (SSLServerSocket)
+                    ssf.createServerSocket(0);
+
+            if (ciphersuites != null) {
+                System.out.println("Server: enable cipher suites: "
+                        + java.util.Arrays.toString(ciphersuites));
+                ssocket.setEnabledCipherSuites(ciphersuites);
+            }
+
+            return new SSLServer(ssocket);
+        }
+    }
+
+    static class SSLClient implements AutoCloseable {
+
+        private final SSLSocket socket;
+
+        private SSLClient(SSLSocket socket) {
+            this.socket = socket;
+        }
+
+        void connect() throws IOException {
+            System.out.println("Client: connect to server");
+            try (
+                    BufferedInputStream bis = new BufferedInputStream(
+                            socket.getInputStream());
+                    BufferedOutputStream bos = new BufferedOutputStream(
+                            socket.getOutputStream())) {
+                bos.write('x');
+                bos.flush();
+
+                int read = bis.read();
+                if (read < 0) {
+                    throw new IOException("Client: couldn't read a response");
+                }
+                socket.getSession().invalidate();
+            }
+        }
+
+        String[] getEnabledCiperSuites() {
+            return socket.getEnabledCipherSuites();
+        }
+
+        String getNegotiatedCipherSuite() {
+            return socket.getSession().getCipherSuite();
+        }
+
+        @Override
+        public void close() throws Exception {
+            if (!socket.isClosed()) {
+                try {
+                    socket.close();
+                } catch (IOException e) {
+                    System.out.println("Client: close: " + e);
+                }
+            }
+        }
+
+        static SSLClient init(int port)
+                throws NoSuchAlgorithmException, IOException {
+            return init(port, null);
+        }
+
+        static SSLClient init(int port, String ciphersuite)
+                throws NoSuchAlgorithmException, IOException {
+            SSLContext context = SSLContext.getDefault();
+            SSLSocketFactory ssf = (SSLSocketFactory)
+                    context.getSocketFactory();
+            SSLSocket socket = (SSLSocket) ssf.createSocket("localhost", port);
+
+            if (ciphersuite != null) {
+                System.out.println("Client: enable cipher suite: "
+                        + ciphersuite);
+                socket.setEnabledCipherSuites(new String[] { ciphersuite });
+            }
+
+            return new SSLClient(socket);
+        }
+
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/ciphersuites/ECCurvesconstraints.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2016, 2017, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8148516
+ * @summary Improve the default strength of EC in JDK
+ * @modules jdk.crypto.ec
+ * @run main/othervm ECCurvesconstraints PKIX
+ * @run main/othervm ECCurvesconstraints SunX509
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.interfaces.ECPrivateKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+
+public class ECCurvesconstraints {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    //
+    // EC curve: secp224k1
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBCzCBugIEVz2lcjAKBggqhkjOPQQDAjAaMRgwFgYDVQQDDA93d3cuZXhhbXBs\n" +
+        "ZS5vcmcwHhcNMTYwNTE5MTEzNzM5WhcNMTcwNTE5MTEzNzM5WjAaMRgwFgYDVQQD\n" +
+        "DA93d3cuZXhhbXBsZS5vcmcwTjAQBgcqhkjOPQIBBgUrgQQAIAM6AAT68uovMZ8f\n" +
+        "KARn5NOjvieJaq6h8zHYkM9w5DuN0kkOo4KBhke06EkQj0nvQQcSvppTV6RoDLY4\n" +
+        "djAKBggqhkjOPQQDAgNAADA9AhwMNIujM0R0llpPH6d89d1S3VRGH/78ovc+zw51\n" +
+        "Ah0AuZ1YlQkUbrJIzkuPSICxz5UfCWPe+7w4as+wiA==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8
+    static String targetPrivateKey =
+        "MIGCAgEAMBAGByqGSM49AgEGBSuBBAAgBGswaQIBAQQdAPbckc86mgW/zexB1Ajq\n" +
+        "38HntWOjdxL6XSoiAsWgBwYFK4EEACChPAM6AAT68uovMZ8fKARn5NOjvieJaq6h\n" +
+        "8zHYkM9w5DuN0kkOo4KBhke06EkQj0nvQQcSvppTV6RoDLY4dg==";
+
+    static String[] serverCerts = {trustedCertStr};
+    static String[] serverKeys  = {targetPrivateKey};
+    static String[] clientCerts = {trustedCertStr};
+    static String[] clientKeys  = {targetPrivateKey};
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(false);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+        try {
+            sslSocket.setSoTimeout(5000);
+            sslSocket.setSoLinger(true, 5);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+
+            throw new Exception("EC curve secp224k1 should be disabled");
+        } catch (IOException she) {
+            // expected exception: no cipher suites in common
+            System.out.println("Expected exception: " + she);
+        } finally {
+            sslSocket.close();
+            sslServerSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = generateSSLContext(true);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+        try {
+            sslSocket.setSoTimeout(5000);
+            sslSocket.setSoLinger(true, 5);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+
+            throw new Exception("EC curve secp224k1 should be disabled");
+        } catch (IOException she) {
+            // expected exception: Received fatal alert
+            System.out.println("Expected exception: " + she);
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;             // trust manager
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+    }
+
+    private static SSLContext generateSSLContext(boolean isClient)
+            throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        ByteArrayInputStream is =
+                    new ByteArrayInputStream(trustedCertStr.getBytes());
+        Certificate trusedCert = cf.generateCertificate(is);
+        is.close();
+
+        ks.setCertificateEntry("Export Signer", trusedCert);
+
+        String[] certStrs = null;
+        String[] keyStrs = null;
+        if (isClient) {
+            certStrs = clientCerts;
+            keyStrs = clientKeys;
+        } else {
+            certStrs = serverCerts;
+            keyStrs = serverKeys;
+        }
+
+        for (int i = 0; i < certStrs.length; i++) {
+            // generate the private key.
+            String keySpecStr = keyStrs[i];
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("EC");
+            ECPrivateKey priKey =
+                    (ECPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            String keyCertStr = certStrs[i];
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = new Certificate[2];
+            chain[0] = keyCert;
+            chain[1] = trusedCert;
+
+            // import the key entry.
+            ks.setKeyEntry("key-entry-" + i, priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(ks, passphrase);
+
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        ks = null;
+
+        return ctx;
+    }
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new ECCurvesconstraints();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ECCurvesconstraints() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died, because of " + e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died, because of " + e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/Cert.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * The certificates and corresponding private keys used by the test.
+ * All of certificates uses relative weak key size and hash algorithm, then
+ * all JDK releases can load them. Accordingly, a custom java.security file is
+ * provided to make sure such weak key sizes and algorithms are not blocked by
+ * any JDK build.
+ */
+public enum Cert {
+
+    // This certificate is generated by the below command:
+    // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 \
+    //     -pkeyopt rsa_keygen_pubexp:65537 -out key.pem
+    // openssl req -x509 -new -days 7300 -key key.pem \
+    //     -subj "/CN=RSA-2048-SHA256" -sha256 -out cer.pem
+    RSA_2048_SHA256(
+            KeyAlgorithm.RSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDFTCCAf2gAwIBAgIUe8nlNUPJa9Iy57Cy5JM49bCzWdkwDQYJKoZIhvcNAQEL\n" +
+            "BQAwGjEYMBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MB4XDTE5MDIyNzA3NDkwMVoX\n" +
+            "DTM5MDIyMjA3NDkwMVowGjEYMBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MIIBIjAN\n" +
+            "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Clo5Prh1AdHSdM7G85B6K20bjSn\n" +
+            "bydcWxa7vQDEgFid1Ne8XRbugv5i8I7kGv2sTl99fopHeJcXHJvQGg7KVPgZqH0Z\n" +
+            "S7ZImlT5f4FYFj8sKnM5wx2P2AxcbO8ktSox0qIgtsHsCd7SusczylqEvSUrcqEe\n" +
+            "V58LtoWH+trsWoSBDlHRew2eD6ZGyQTM8VFqbt9oF2XXW22JiuP+cSvb+p5qSCy5\n" +
+            "dGpdPCJpPB/9HpChZl/r+VsqpbHwUPEVu9/FG0SVjpcqvJojYrgglb1PvJxLqceN\n" +
+            "DPOirwxnnEdiu5j0xC6RhOkbcxTGtS0VgEEC1+HyY+KeauZJOrw2x1ZmxQIDAQAB\n" +
+            "o1MwUTAdBgNVHQ4EFgQUSSj0EFZWTSFr91nTUE2MrJdrJGowHwYDVR0jBBgwFoAU\n" +
+            "SSj0EFZWTSFr91nTUE2MrJdrJGowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" +
+            "AQsFAAOCAQEAW9uuS2ZpG1ytpNA0g20m29R/DVSnygdfp8r/xeaWgdol4H2syPzg\n" +
+            "xok3PLkxkSpBv6CgIPXBzy/iXSMlkX0mUKEO3aQnJ8MoZ5Tzu3Bkp2fTugRQuTRi\n" +
+            "iNWQjsMoupsrTXIZhJ64jkDCnlFADPAdvVqQV01yZcKW98sj3TyaT7TJuYX9mU+V\n" +
+            "OuICkS1LE5NssuyLodxpfqpjBMtVovSKZ57JvO36G6riftnjr3FBf8ukWFK2/UfP\n" +
+            "DaHyFQ+NewbjPy7N+taFlLHS7ELwZVQQ42t8JeHRuF5IVvlp1UjTgXC5NuhOBwQY\n" +
+            "2dXFFroT0vXetn7Fr51zENPP3/TGeaoQnw==\n" +
+            "-----END CERTIFICATE-----",
+            "308204be020100300d06092a864886f70d0101010500048204a8308204a40201" +
+            "000282010100d42968e4fae1d4074749d33b1bce41e8adb46e34a76f275c5b16" +
+            "bbbd00c480589dd4d7bc5d16ee82fe62f08ee41afdac4e5f7d7e8a477897171c" +
+            "9bd01a0eca54f819a87d194bb6489a54f97f8158163f2c2a7339c31d8fd80c5c" +
+            "6cef24b52a31d2a220b6c1ec09ded2bac733ca5a84bd252b72a11e579f0bb685" +
+            "87fadaec5a84810e51d17b0d9e0fa646c904ccf1516a6edf681765d75b6d898a" +
+            "e3fe712bdbfa9e6a482cb9746a5d3c22693c1ffd1e90a1665febf95b2aa5b1f0" +
+            "50f115bbdfc51b44958e972abc9a2362b82095bd4fbc9c4ba9c78d0cf3a2af0c" +
+            "679c4762bb98f4c42e9184e91b7314c6b52d15804102d7e1f263e29e6ae6493a" +
+            "bc36c75666c502030100010282010028f1f4f47c16a93cde5d390ee746df2170" +
+            "a4a9c02fb01c008ef3cc37a5b646aed387083baa1b8adc6d0bdb3138849d006b" +
+            "ffb1d0820f590e8fbf4db2d3d496e7df19d4929017348ebe7a37cc8bc1dc4944" +
+            "d4cc781157db32eeefc7763fb756f55699438701d5f3f1b4e9a7182fad5880c8" +
+            "73a223c61f52ea87c72d7f14511906af61d7fa190b02854471d4bdb77dac34ef" +
+            "46a3af3f39dff1c8844cad7f74f9936fbcc22bed6b139f47dc215048ddf02f60" +
+            "a24703b292be106ea4f01ec0839466666d9c3dc8488b353dccdd5f90bd4b5bb9" +
+            "4493b7da219ec4962fe6a427f6d69e2764065212c5accdbed3aa36a18d540e55" +
+            "192e63db9f6bdfc90ec52b89714d0102818100f7c35a70ee7d6aabd7feb590f6" +
+            "30ce9c28299f3431ebcd3c89ec9424cf68c626ee4f6ff0748ffc0ad810a9f6dd" +
+            "2b203c8fa7f516483545822e6c963b9f6a1687aca663be061aadcca920b09699" +
+            "bd7d2e8973bafe9ef11e19a27c10befe3e8919c141d04e5aab2990cc061c6798" +
+            "5d3da742a3c8c62b68a8ccb4af21c1c935bdcd02818100db37101251d805b8d6" +
+            "12749d8780cce9e4ff8fc58313e4192fbf9018dc2a8875beff70ea2ebaa24058" +
+            "d3de6eab4be66b0bb81c04f0fa29bad0f787776ed2e6ab7b7d9814ce7721cadd" +
+            "cc3f500ddfd73ae9def4d92a79e4a1662da16dbfc52d60507308286cf592ed8b" +
+            "9911089c4ec7dba3fcd64926b55d137d41f6de454694d902818100af6b582077" +
+            "2ac318d2401bcb7c13886555a64a7b09115be98df9bbd5e827d58c00d4ab7bc2" +
+            "fba2c706bd9da9146491596f98ca553160ce4ae295ad349fa4dc38c94bb178fc" +
+            "176d9066faa72ca9c358db572462741e92b6ee0d75ebe15e5f66709ebcfb404e" +
+            "bfbb1932eaecb7885013f3d5a1e2e83419d0d1c6e7ec6da9096ccd0281810099" +
+            "81fc922797f3a1d4dec5a4ce8fc66effba6aae7034cca54a8785dbb2c96217ba" +
+            "315c9bd12f469172e2a2bfb2da8ab769547ae286f157a987cddea2270c2f15e4" +
+            "7b35b554439e79564a4207c83f7893bbd43277a4c408f370ff012d3e7e506142" +
+            "d4dae09c3477b83aea6c40305d069d6b3f91bb560ce8e9cdec1478dfe0263902" +
+            "818002b66c71380142c3e606bfc598b4060f6833ac80e16d08aea40f4837191d" +
+            "34a3c85b91c3043c6ebb2c651a7fbb89539f5621820f792a5279a947c51f47b7" +
+            "1b6051c5a81d2d1c30dfa1f93cb57af1d7ee7862e8d90e33bd5c80f14aa9471b" +
+            "a2ea7aacddbb44d1a5e60f5fac437ca50cd56e237936fd3e9d034efc3e3c6710" +
+            "4c08"),
+
+    // This certificate is generated by the below command:
+    // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 \
+    //     -pkeyopt rsa_keygen_pubexp:65537 -out key.pem
+    // openssl req -x509 -new -days 7300 -key key.pem \
+    //     -subj "/CN=EXAMPLE" -sha256 -out cer.pem
+    EXAMPLE_RSA_2048_SHA256(
+            KeyAlgorithm.RSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIDBTCCAe2gAwIBAgIUD+8I14TmOfEfxtD6hgnhhK8ARCAwDQYJKoZIhvcNAQEL\n" +
+            "BQAwEjEQMA4GA1UEAwwHRVhBTVBMRTAeFw0xOTAyMjcwODAzNDhaFw0zOTAyMjIw\n" +
+            "ODAzNDhaMBIxEDAOBgNVBAMMB0VYQU1QTEUwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" +
+            "DwAwggEKAoIBAQChKYq85df7kUnf35qAfxW/OnqCgn/5FNwlWAwHLlEiHpK+k7jD\n" +
+            "8S6LVbw55I/4J3lehIHcIapGdmqh9ijUc2aNxTJ33z+/TTu2n+KlWmGj0G7ovTXk\n" +
+            "TbWptdgk5ro8DCr8I8YcvwdLekwH4AkRL6jSyiqsqlGZYLIxDd4l0CwSt5orbu/y\n" +
+            "+2UtM4DEOEswrxdP9UAd+W0On4AWaFIEbfuFaLZXHadvKxidnaCmudOJry6NjFWn\n" +
+            "+3PmIWNhZJitD0gq8FG3pvY502fLqHX95pigWCkDtrDNiqReXgVvZFWPaSMs065y\n" +
+            "n2ClShbzTs8pqJp8oBde9Iwi3RKwkew8I2iJAgMBAAGjUzBRMB0GA1UdDgQWBBTL\n" +
+            "3w5XucuEre5nQiaKnqi4s7ldBjAfBgNVHSMEGDAWgBTL3w5XucuEre5nQiaKnqi4\n" +
+            "s7ldBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBo51E5U5H7\n" +
+            "kXkI1LaGDs35dOOtrPQQQ7DzhQACUDfyYB8/BBUlYHPegS2ca/l1mkD2P/GNyZbN\n" +
+            "r4eRoOujfU59gOwH4+MEs/4zUKicajTGUPCbJ56heipHunHzj+2nj3ok5PI0MoI1\n" +
+            "soQfRV1FshfWAni7E49L1QI/PQrQ2cPR/1dvkB06JCIn0GoTxd8E76VCJz576xnd\n" +
+            "XgjiadVbjMYDH9XJEy6eQT6vY5WeGOQC2XwSE3mS6G+Z9jlwIswa8RrKGtKqFGK1\n" +
+            "6yse9zfJv64X8tQwnrkatCx4shJwDUet6wJQzm0/NMPfquoxz7QHF2NsLlNky+fY\n" +
+            "fZjMnoO3J1nV\n" +
+            "-----END CERTIFICATE-----",
+            "308204bd020100300d06092a864886f70d0101010500048204a7308204a30201" +
+            "000282010100a1298abce5d7fb9149dfdf9a807f15bf3a7a82827ff914dc2558" +
+            "0c072e51221e92be93b8c3f12e8b55bc39e48ff827795e8481dc21aa46766aa1" +
+            "f628d473668dc53277df3fbf4d3bb69fe2a55a61a3d06ee8bd35e44db5a9b5d8" +
+            "24e6ba3c0c2afc23c61cbf074b7a4c07e009112fa8d2ca2aacaa519960b2310d" +
+            "de25d02c12b79a2b6eeff2fb652d3380c4384b30af174ff5401df96d0e9f8016" +
+            "6852046dfb8568b6571da76f2b189d9da0a6b9d389af2e8d8c55a7fb73e62163" +
+            "616498ad0f482af051b7a6f639d367cba875fde698a0582903b6b0cd8aa45e5e" +
+            "056f64558f69232cd3ae729f60a54a16f34ecf29a89a7ca0175ef48c22dd12b0" +
+            "91ec3c236889020301000102820100655c9e60ce62b85b99ce0f71ba2db3fcd1" +
+            "07ea7baf8776823b8e940a142c7d3c23696fb97eab7b6db11fb07dbbbb0500c5" +
+            "dcab5c4b642feb1c87ff2d90e97fefdcbe303c9e7870580535ac33f9937d9783" +
+            "9a281ef41798114448cc74bd5f34fbf8177bebea8de8ffe33ff4bd5f2ccd8ebe" +
+            "0e7708ac47be54749bd7438b199d2f134b71efc513827f260c0f74f1fc32f45b" +
+            "e5d510844777fcd2a486bc02c080d120d1c32336000ece743ea755f79f60a44a" +
+            "5e619ceb1caa873d847715616874d13c2ff1fe9f9f81d8fc83e83fb035bce8d9" +
+            "ed8f5caa41626d323551311b1d8d8f06785e3700d45e4d771157b22826efe553" +
+            "7a5892ad3bf3f915ec25342a8c7a3d02818100d19c03d857442bbaedb41b741e" +
+            "8e93d295940fdfc455898463ad96b0089ee68d90b787848b7aed6bb735c7e4b9" +
+            "7b22e867000d8e4b4ede4b155c34fd88c10244917912c048d023757bd758a117" +
+            "764aa80434c5c9636ec125574667ffe01af856f4517d06b6831ad50f16b26bba" +
+            "67a7125e158988c98b817dbb0928efa00c3ed702818100c4d49f7f3bf36586aa" +
+            "519bf2841c459c1863e71c08a9111344e51fcf5ff4267420fd9ffc9f72288e44" +
+            "b56bdae4eaa669e5e350afe4b4402be4af54d5dbc8b5dc5f5b6bb79df4fd17a5" +
+            "225287947783b5327b5dedf02733fb534514cc05fde1dcfceb8b537ad3c163a8" +
+            "8f36a60e2fb17fa6d9a0f3fca444f349eed9f07823879f02818100a5e9eb753c" +
+            "261ec338d23e84dc8718e53036e195cacfb6294fc920a4b83e26da59799c5043" +
+            "238b789ead784b48b1fa40a0fefebbea4a44548454d730f4256a8921e906f9a2" +
+            "e8f59851ed741f16f63043ec0865a2720d41df2fc4f01f2ea1ca7ef1a6eae2fc" +
+            "66ac3f8750fceb9ec1db1203dce25f9ec0c93fdf6371beb31dde430281807852" +
+            "be59ea4d25504847f13c34948fdd176fe2f4d93a790cbd7e0f8f16ca4ac38cf3" +
+            "5e5cf11fb93917398c805896353ae164af8b8714c571cfaf7afded086a5c1812" +
+            "ebeb686d3e56b9051d4c726f091db8897fe7177aefa500c7672a3db370e245de" +
+            "bbe24160b784f3a2f0b65c4fbd831a7d498e3d70321243acf69fb0e18f630281" +
+            "8065f0a2f257f8bf1d57e3f1b72c9a664ca92630985ee5ba35438e57a1df67a6" +
+            "f6b380907f5b7f9bdd2ddc63385615c5ca3c0dcbedfdc3f18433160855824712" +
+            "eaaeb318774478427dfb58135715cf82730a743dd8448984450905c28a6a97a0" +
+            "5f4aaad616978c07c5957c4f1945073f333df4337557bd6b754953f71df7a03c" +
+            "ec"),
+
+    // This certificate is generated by the below commands:
+    // openssl genpkey -genparam -algorithm dsa -pkeyopt dsa_paramgen_bits:2048 \
+    //     -pkeyopt dsa_paramgen_q_bits:256 -out param.pem
+    // openssl genpkey -paramfile param.pem -out key.pem
+    // openssl req -x509 -new -key key.pem -days 7300 \
+    //     -subj "/CN=DSA-2048-SHA256" -sha256 -out cer.pem
+    DSA_2048_SHA256(
+            KeyAlgorithm.DSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIEezCCBCCgAwIBAgIUYbBHFrJkO9EokOROEScK0dr3aVowCwYJYIZIAWUDBAMC\n" +
+            "MBoxGDAWBgNVBAMMD0RTQS0yMDQ4LVNIQTI1NjAeFw0xOTAxMTYwNjA4NTJaFw0z\n" +
+            "OTAxMTEwNjA4NTJaMBoxGDAWBgNVBAMMD0RTQS0yMDQ4LVNIQTI1NjCCA0cwggI5\n" +
+            "BgcqhkjOOAQBMIICLAKCAQEAnGTeaC+MitQykXl2UcGtJhkelRhBalZuzR9fh8Xf\n" +
+            "swSj2auVzhjkQfns6E14X72XLYDwHPQilh4ZSiC1cX7bpvohJ7CjbouGnT78Gwf0\n" +
+            "pfVMRBRfbNiwBQzFtzehAqlLPXyHWCPxAzW0EgzZh8asIofBEGmGh6sxlpXbEcCS\n" +
+            "Ra5Q2vdDRVksm4APHKwbS1F6L/0QDvjDAudWyLFdFMSBuoyeFwCf7Gr5lcVi538h\n" +
+            "MliXSAhJ7SXe4B9K/5/VicuzAffE+EZsZZuJKeQ4oHz8xtycdMcW86Iag1i/POzD\n" +
+            "0Z7c5p9j1zDgms1ZRSz4fd7YgNGjmmf6dYJlZmCX4w9YiwIhALnVATHxZmk7G1kf\n" +
+            "LGX7SMeflAhA/D3EPA5QWdgTc0orAoIBAGYTWMnKHBF4oMKUsx6lF6KvSrqFQ0+j\n" +
+            "mWN1RNAGiVYm/Js9sc7jolZCbVTWM7GblO2DxiKed3FtcL3xw4P6l3GU7kFthsjh\n" +
+            "bHbMG58s5JVboLX50wZo1uBOb0kRcZYjYTfUwbBYpGNnl7xfQsZ/Bxq/wzyn4gxb\n" +
+            "+C0pu/vzmko+opKfFr9a2EL+ADvQhPd6y/L0YcpiTihvfXDWu+n3bNlwhUZYevux\n" +
+            "SPVkQH3h5YEqXePF7UeY506/2sr41/xCbCkuH+Ob77Cy1IjMqr4OpXzj6wCSjlFy\n" +
+            "Re66yqsjGpuBeTtsn9lKmlFVl4QUdw7XYbRubafNFEdd5IazMflCcgMDggEGAAKC\n" +
+            "AQEAnF3/TT0nYzfwY6/+lmoqoBtGU4of7RK4U3Jdhf6dj755GwgsPGAz3Rzh/hq/\n" +
+            "B3fuyrtnE/aU0EK1dtRNqnKeFsMCURBi3sWYYe7vamw5TukFMSUOuH76v75b26c+\n" +
+            "nTfZF30iDz+66Z5gcOSwhz9aLCnF/wYwijnzagnCF4m0Nhwsjtz4qECMPfL/Rkx8\n" +
+            "s83tUF53mx5o8WCYMNr4yJGcHEkautvZN05zwoxZTPKZNngWeCUAY07XwOYHTUvx\n" +
+            "C9Sxiom9k1pZPbHZnGpUx96at2dMoeTeHR6xF/0QpiIb4wLpOg/CRxsopBmhEl0S\n" +
+            "BEXYNIcrXLwVBLvJD6H44DxRiqNTMFEwHQYDVR0OBBYEFCr6C8Bl7wjz5L3cYMG3\n" +
+            "/ZFe7Ee0MB8GA1UdIwQYMBaAFCr6C8Bl7wjz5L3cYMG3/ZFe7Ee0MA8GA1UdEwEB\n" +
+            "/wQFMAMBAf8wCwYJYIZIAWUDBAMCA0gAMEUCIArByiqjCG1ZuOVY91OPa9g8q60y\n" +
+            "/BSRWRgikEuq3AbgAiEAoZoKXW80FTMxv/9tFy0N7OrUV4rc9+AUBSTuRCuTAk4=\n" +
+            "-----END CERTIFICATE-----",
+            "308202640201003082023906072a8648ce3804013082022c02820101009c64de" +
+            "682f8c8ad43291797651c1ad26191e9518416a566ecd1f5f87c5dfb304a3d9ab" +
+            "95ce18e441f9ece84d785fbd972d80f01cf422961e194a20b5717edba6fa2127" +
+            "b0a36e8b869d3efc1b07f4a5f54c44145f6cd8b0050cc5b737a102a94b3d7c87" +
+            "5823f10335b4120cd987c6ac2287c110698687ab319695db11c09245ae50daf7" +
+            "4345592c9b800f1cac1b4b517a2ffd100ef8c302e756c8b15d14c481ba8c9e17" +
+            "009fec6af995c562e77f21325897480849ed25dee01f4aff9fd589cbb301f7c4" +
+            "f8466c659b8929e438a07cfcc6dc9c74c716f3a21a8358bf3cecc3d19edce69f" +
+            "63d730e09acd59452cf87dded880d1a39a67fa758265666097e30f588b022100" +
+            "b9d50131f166693b1b591f2c65fb48c79f940840fc3dc43c0e5059d813734a2b" +
+            "02820100661358c9ca1c1178a0c294b31ea517a2af4aba85434fa399637544d0" +
+            "06895626fc9b3db1cee3a256426d54d633b19b94ed83c6229e77716d70bdf1c3" +
+            "83fa977194ee416d86c8e16c76cc1b9f2ce4955ba0b5f9d30668d6e04e6f4911" +
+            "7196236137d4c1b058a4636797bc5f42c67f071abfc33ca7e20c5bf82d29bbfb" +
+            "f39a4a3ea2929f16bf5ad842fe003bd084f77acbf2f461ca624e286f7d70d6bb" +
+            "e9f76cd9708546587afbb148f564407de1e5812a5de3c5ed4798e74ebfdacaf8" +
+            "d7fc426c292e1fe39befb0b2d488ccaabe0ea57ce3eb00928e517245eebacaab" +
+            "231a9b81793b6c9fd94a9a5155978414770ed761b46e6da7cd14475de486b331" +
+            "f942720304220220509dd213cc9769e93825063a4a60500f67c4b979f6504b2f" +
+            "ccdbefb3ab8fe6da"),
+
+    // This certificate is generated by the below commands:
+    // openssl genpkey -genparam -algorithm dsa -pkeyopt dsa_paramgen_bits:2048 \
+    //     -pkeyopt dsa_paramgen_q_bits:256 -out param.pem
+    // openssl genpkey -paramfile param.pem -out key.pem
+    // openssl req -x509 -new -key key.pem -days 7300 \
+    //     -subj "/CN=EXAMPLE" -sha256 -out cer.pem
+    EXAMPLE_DSA_2048_SHA256(
+            KeyAlgorithm.DSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIEaTCCBA+gAwIBAgIUckU2myqkWak+Svv0FFJX91vv1jMwCwYJYIZIAWUDBAMC\n" +
+            "MBIxEDAOBgNVBAMMB0VYQU1QTEUwHhcNMTkwMTE2MDYwODUzWhcNMzkwMTExMDYw\n" +
+            "ODUzWjASMRAwDgYDVQQDDAdFWEFNUExFMIIDRjCCAjkGByqGSM44BAEwggIsAoIB\n" +
+            "AQDGmXUxMKzLIVUQUy4lu4fbnv8fRXtWIbv1jxWATCNFiFt4cUxrr7GVC16MGrgm\n" +
+            "FtMIHXWwFlq2wTL0RhVp2WPIPQzxCwQFivQjpdewVCB1BoJ1ozlvQjU4hri5Ymdt\n" +
+            "ebe90uT8NsvrQrSKYCl+/pPNiZKT8oX1aKzRYPQLn0bVXUicWlACoLfHGM4irjEC\n" +
+            "4JezC/tdLleeNYNpy2/dKYu/atyN/u0d+dPRLWBCw6/qCRn1yRAv04GC3WYBlSXz\n" +
+            "f9OKlCH5kfm9sLyatz/RWDqOb/YWW2Rk7UTKAnoTAyB+I9yUXg6Gad2csNkxXv55\n" +
+            "9oJAhdhsOS5cdBoqlZEahIFBAiEAjiMCVBGpnAxjb2dXM/Eec7EfThflQXbl33Zn\n" +
+            "Uq3AAsUCggEAaBNP9Uttfs1eV/38aurLd3T1OiM0CF7DPxE0qpSM9dQz9cKZajIE\n" +
+            "lsVTGOLBC5/+VSat9t1VG+JoyvSspkvk97/mxx0WCz/QAYTdwCXVuMuSv+EqeOMP\n" +
+            "lCxEdbOS8pfD8shOK+pnDSHMJvURYxB+fJkHHeXfwesH3632Vq0GlJ8PgXH5NLHM\n" +
+            "MWv7oZjyZMnGWDq2taJcZZG5ETNda2fATNCF9Al430MUxie2Sp50vA1KEtyUqMu+\n" +
+            "CLpyOynPHi96TWHNfD23TmKFVN9Uh2nUNIpUk8NMKBwg2O7FvvNnKfbl44ikuCnc\n" +
+            "06U7SdF3y8NRdwyayMI3BkOsV8mkoMwUgAOCAQUAAoIBADK2c1Gl3+6zrFU8Uhro\n" +
+            "5lFnDy3UYXINpdtWR/8T0FJ6YMax70VCkyxucq3AUnmq9AQtFijjmXDnxzD5g7IS\n" +
+            "zOU/28Kg1Mmw26uzrpUZPiixNU7v/xzE37M0Ig3VCEQ9mw57/yv8gwZurHtsokGt\n" +
+            "k0lzH/krhYPCOpskg6NulGq5lGsnNVdPkSkiAWZFHTysgKgxvMUxXj0bUm4ZyNw6\n" +
+            "Lp2bFHKbmSeTy3OLo/Kvd7BIjhV+Bi5LFh7h8spf6SC7qyEm0X7Keu+61xkFHU8a\n" +
+            "aghnGQYwuzpTp+hsbAJdHwVLw9ElqEoaVp3rAmxtsdzqhZSxcMZoypbjEJpiZ1/v\n" +
+            "fQCjUzBRMB0GA1UdDgQWBBRTPXqHl7VKr5U94p9c882ge9DOXzAfBgNVHSMEGDAW\n" +
+            "gBRTPXqHl7VKr5U94p9c882ge9DOXzAPBgNVHRMBAf8EBTADAQH/MAsGCWCGSAFl\n" +
+            "AwQDAgNHADBEAiAOQxtKiMImXKWQvUKZxoUc+chXRxAj3UD3Zj7RksPF2AIgf8HG\n" +
+            "hOnr3hzIej3Da2Ty9RTittcgZ14boraO/Vlx9Jo=\n" +
+            "-----END CERTIFICATE-----",
+            "308202640201003082023906072a8648ce3804013082022c0282010100c69975" +
+            "3130accb215510532e25bb87db9eff1f457b5621bbf58f15804c2345885b7871" +
+            "4c6bafb1950b5e8c1ab82616d3081d75b0165ab6c132f4461569d963c83d0cf1" +
+            "0b04058af423a5d7b0542075068275a3396f42353886b8b962676d79b7bdd2e4" +
+            "fc36cbeb42b48a60297efe93cd899293f285f568acd160f40b9f46d55d489c5a" +
+            "5002a0b7c718ce22ae3102e097b30bfb5d2e579e358369cb6fdd298bbf6adc8d" +
+            "feed1df9d3d12d6042c3afea0919f5c9102fd38182dd66019525f37fd38a9421" +
+            "f991f9bdb0bc9ab73fd1583a8e6ff6165b6464ed44ca027a1303207e23dc945e" +
+            "0e8669dd9cb0d9315efe79f6824085d86c392e5c741a2a95911a848141022100" +
+            "8e23025411a99c0c636f675733f11e73b11f4e17e54176e5df766752adc002c5" +
+            "0282010068134ff54b6d7ecd5e57fdfc6aeacb7774f53a2334085ec33f1134aa" +
+            "948cf5d433f5c2996a320496c55318e2c10b9ffe5526adf6dd551be268caf4ac" +
+            "a64be4f7bfe6c71d160b3fd00184ddc025d5b8cb92bfe12a78e30f942c4475b3" +
+            "92f297c3f2c84e2bea670d21cc26f51163107e7c99071de5dfc1eb07dfadf656" +
+            "ad06949f0f8171f934b1cc316bfba198f264c9c6583ab6b5a25c6591b911335d" +
+            "6b67c04cd085f40978df4314c627b64a9e74bc0d4a12dc94a8cbbe08ba723b29" +
+            "cf1e2f7a4d61cd7c3db74e628554df548769d4348a5493c34c281c20d8eec5be" +
+            "f36729f6e5e388a4b829dcd3a53b49d177cbc351770c9ac8c2370643ac57c9a4" +
+            "a0cc1480042202201ba738489c54dddd5ffbf0009ef9d11851182235a251a410" +
+            "4a6354181ecd0348"),
+
+    // This certificate is generated by the below commands:
+    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
+    //     -pkeyopt ec_param_enc:named_curve -out key.pem
+    // openssl req -x509 -new -days 7300 -key key.pem \
+    //     -subj "/CN=ECDSA-SECP256-SHA256" -sha256 -out cer.pem
+    ECDSA_PRIME256V1_SHA256(
+            KeyAlgorithm.EC,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIBkzCCATmgAwIBAgIUVW+Rj8muf1DO8yUB9NSEDkD8oYowCgYIKoZIzj0EAwIw\n" +
+            "HzEdMBsGA1UEAwwURUNEU0EtU0VDUDI1Ni1TSEEyNTYwHhcNMTkwMjI3MTEwNzA0\n" +
+            "WhcNMzkwMjIyMTEwNzA0WjAfMR0wGwYDVQQDDBRFQ0RTQS1TRUNQMjU2LVNIQTI1\n" +
+            "NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJPHqflVA59hR/sBM64OOY2/PTTx\n" +
+            "kZZhKcVV8vEkWRWvDV2u2F+lbRQoEoe8bwfGgQgGJIdc+dz9/TVAaYlitaKjUzBR\n" +
+            "MB0GA1UdDgQWBBRS9gbMeeA7j7QdipPufKn3jI3hKTAfBgNVHSMEGDAWgBRS9gbM\n" +
+            "eeA7j7QdipPufKn3jI3hKTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA\n" +
+            "MEUCIDH0b3EewcoZUeSo0c2pNSWGCeRlZI49dASDbZ3A0jdTAiEAy/dM9LwYvyLl\n" +
+            "yuWq4yTouCdzfQwR9QXg3ohRMhnASlg=\n" +
+            "-----END CERTIFICATE-----",
+            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
+            "01010420ae670b91bae99a9752f2b7e26ab9c0e98636f0b0040d78f2ea4081f8" +
+            "e57c72e0a1440342000493c7a9f955039f6147fb0133ae0e398dbf3d34f19196" +
+            "6129c555f2f1245915af0d5daed85fa56d14281287bc6f07c681080624875cf9" +
+            "dcfdfd3540698962b5a2"),
+
+    // This certificate is generated by the below commands:
+    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
+    //     -pkeyopt ec_param_enc:named_curve -out key.pem
+    // openssl req -x509 -new -days 7300 -key key.pem \
+    //     -subj "/CN=EXAMPLE" -sha256 -out cer.pem
+    EXAMPLE_ECDSA_PRIME256V1_SHA256(
+            KeyAlgorithm.EC,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIBeTCCAR+gAwIBAgIUH6kQ0NfopvszxUwZ58KhMicqgCwwCgYIKoZIzj0EAwIw\n" +
+            "EjEQMA4GA1UEAwwHRVhBTVBMRTAeFw0xOTAyMjcxMTA5MTJaFw0zOTAyMjIxMTA5\n" +
+            "MTJaMBIxEDAOBgNVBAMMB0VYQU1QTEUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\n" +
+            "AASbW2bDwNxTHAzN7aW/OD/ywfa0A4bPKF3Qw4U4nLFBHhbbEmDrIkRWqU56UUDt\n" +
+            "fnTZnBCJtm4sH8o9D1D9UZVFo1MwUTAdBgNVHQ4EFgQUEEpzWKgPritmUQNEcQhz\n" +
+            "bB+5KuUwHwYDVR0jBBgwFoAUEEpzWKgPritmUQNEcQhzbB+5KuUwDwYDVR0TAQH/\n" +
+            "BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBjeGB0oc6t2fWOaviIMfqRqta64nl6\n" +
+            "Gj8I/JfDH97P1wIhAJ5IC9cxVTiPL/QTxUxRRlTYUboL/+ck1XR9JbZjd/ar\n" +
+            "-----END CERTIFICATE-----",
+            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
+            "010104205dfd6695d259d4047433c0b4520bedcf95130c5c08ba149caddad70d" +
+            "b3b66c1ba144034200049b5b66c3c0dc531c0ccdeda5bf383ff2c1f6b40386cf" +
+            "285dd0c385389cb1411e16db1260eb224456a94e7a5140ed7e74d99c1089b66e" +
+            "2c1fca3d0f50fd519545"),
+
+    // This certificate is generated by the below commands:
+    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
+    //     -pkeyopt ec_param_enc:named_curve -out key.pem
+    // openssl req -new -key key.pem \
+    //     -subj "/CN=EC-RSA-SECP256-SHA256" -sha256 -out csr.pem
+    // openssl x509 -req -CAcreateserial -days 7300 -in csr.pem -sha256 \
+    //     -CA CA.cer -CAkey CA.key -out cer.pem
+    // Actually the CA is RSA_2048_SHA256
+    EC_RSA_PRIME256V1_SHA256(
+            KeyAlgorithm.EC,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIB9TCB3gIUWuMp26pvpTFO08C+ev6W8ZRDwqAwDQYJKoZIhvcNAQELBQAwGjEY\n" +
+            "MBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MB4XDTE5MDIyNzA3NTUwMFoXDTM5MDIy\n" +
+            "MjA3NTUwMFowIDEeMBwGA1UEAwwVRUMtUlNBLVNFQ1AyNTYtU0hBMjU2MFkwEwYH\n" +
+            "KoZIzj0CAQYIKoZIzj0DAQcDQgAEgCoIan3yAA4KVwAO4qrMFF1alcYFzywPHerI\n" +
+            "eje3eQVhFaTecnbm0rTJE66JF8HeNuefd61+v1FqWo95aJ1l9zANBgkqhkiG9w0B\n" +
+            "AQsFAAOCAQEAJIgHTHyPJ5X44JR5ee3N2sYA8C9KGf2YFq/yPQ+pYYIk2gNKqMTH\n" +
+            "IgHzEqpeb1KC8i+F57xD8qL76QZ7YGVueKoU0o2XYO8Fj4Kug9B48uYvw4J025Bf\n" +
+            "emxVzuDwgPNAeQwzfoR4NpMKV6TjA7c1VVNUwnse7jHyzqkQLlNors62U+O2MI/t\n" +
+            "4RM6PDLWuGm9eDZAtifxdjjME9efEXOVi2y/9YAr7hOJKn3r1ie1Txo1N3LXTsLg\n" +
+            "Y0GlCcOiDGD5So6jSn4hY2CyeeEtTOZkloT/2Slpz9MbLzlav8hqnNQDbuSCFnyn\n" +
+            "fQh6yysvdeRm6Yx8bNkA/pxz/Y21fXVWMg==\n" +
+            "-----END CERTIFICATE-----",
+            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
+            "0101042079433b715d94d8de6b423f55ef05c911613dc708339391339bef6ca3" +
+            "c14b419ca14403420004802a086a7df2000e0a57000ee2aacc145d5a95c605cf" +
+            "2c0f1deac87a37b779056115a4de7276e6d2b4c913ae8917c1de36e79f77ad7e" +
+            "bf516a5a8f79689d65"),
+
+    // This certificate is generated by the below commands:
+    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
+    //     -pkeyopt ec_param_enc:named_curve -out key.pem
+    // openssl req -new -key key.pem -subj "/CN=EXAMPLE" -sha256 -out csr.pem
+    // openssl x509 -req -CAcreateserial -days 7300 -in csr.pem -sha256 \
+    //     -CA CA.cer -CAkey CA.key -out cer.pem
+    // Actually the CA is EXAMPLE_RSA_2048_SHA256
+    EXAMPLE_EC_RSA_PRIME256V1_SHA256(
+            KeyAlgorithm.EC,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIB3zCByAIUWm9wgVB1TgdT5lpGNNkWBzuclKQwDQYJKoZIhvcNAQELBQAwEjEQ\n" +
+            "MA4GA1UEAwwHRVhBTVBMRTAeFw0xOTAyMjcwODA0MTNaFw0zOTAyMjIwODA0MTNa\n" +
+            "MBIxEDAOBgNVBAMMB0VYQU1QTEUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASp\n" +
+            "6YAqTEEjuMlG+vKl8XPo2T2wgqY6t+j1R5ySC0YiGesfrwVLTM4V+Ey9PKHoEIVK\n" +
+            "kWNUF5Sb2JdrYIuzb5WdMA0GCSqGSIb3DQEBCwUAA4IBAQBPrIScxw5Nx4DhT5GL\n" +
+            "ngyNBOun0yAwqrxQ3LPheMuN7CH4qehFPDx8MHhmFFjEIDKVRbEEgxiCJAgca7qD\n" +
+            "uLCfESM8KU4bkV4Pjx7/OEQZ3AkQ0UwDvDr/DypPg7TLLyF979OQo+fEaqWKH8Q4\n" +
+            "8Ot8+VUFuwpYhHQlkoPnwFKIuCfDGwYmmHP2btlZ5qBuDDzdo1JVGF8pJ943cfA8\n" +
+            "zRBJGKw8MMJXlfk3yiDSKMji0106SFuGwFJfkrdUnZ+hpeJ7rrrqW7jwLIil8PKf\n" +
+            "Z41UjYM4Ut/6O5SFqueBsC6yxfzrJbd8UZ7ZkfagWMr/AXLK1Sm3ICSPHsQW30mH\n" +
+            "uX+T\n" +
+            "-----END CERTIFICATE-----",
+            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
+            "01010420f1f944e1fc4bd7013b157db5fed23b84a4a1cd3d1a22f40746353185" +
+            "c0d8684da14403420004a9e9802a4c4123b8c946faf2a5f173e8d93db082a63a" +
+            "b7e8f5479c920b462219eb1faf054b4cce15f84cbd3ca1e810854a9163541794" +
+            "9bd8976b608bb36f959d");
+
+    public final KeyAlgorithm keyAlgorithm;
+    public final String certMaterials;
+    public final String privKeyMaterials;
+
+    private Cert(
+            KeyAlgorithm keyAlgorithm,
+            String certMaterials,
+            String privKeyMaterials) {
+        this.keyAlgorithm = keyAlgorithm;
+        this.certMaterials = certMaterials;
+        this.privKeyMaterials = privKeyMaterials;
+    }
+
+    // Two certificates (mainCert and exampleCert) are selected to respect the
+    // specified cipher suite. SNI-associated cases specify exampleCert as desired.
+    public static Cert[] getCerts(CipherSuite cipherSuite) {
+        Cert mainCert = Cert.ECDSA_PRIME256V1_SHA256;
+        Cert exampleCert = Cert.EXAMPLE_ECDSA_PRIME256V1_SHA256;
+        if (cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_RSA
+                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.RSA) {
+            mainCert = Cert.RSA_2048_SHA256;
+            exampleCert = Cert.EXAMPLE_RSA_2048_SHA256;
+        } else if (cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDH_RSA) {
+            mainCert = Cert.EC_RSA_PRIME256V1_SHA256;
+            exampleCert = Cert.EXAMPLE_EC_RSA_PRIME256V1_SHA256;
+        } else if (cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS) {
+            mainCert = Cert.DSA_2048_SHA256;
+            exampleCert = Cert.EXAMPLE_DSA_2048_SHA256;
+        }
+        System.out.printf("mainCert=%s, exampleCert=%s%n",
+                mainCert, exampleCert);
+        return new Cert[] { mainCert, exampleCert };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/Client.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/*
+ * A simple SSL socket client.
+ */
+public class Client {
+
+    private final SSLSocket socket;
+
+    public Client(SSLContext context) throws Exception {
+        SSLSocketFactory socketFactory = context.getSocketFactory();
+        socket = (SSLSocket) socketFactory.createSocket();
+        socket.setSoTimeout(Utils.TIMEOUT);
+    }
+
+    public Client(Cert... certs) throws Exception {
+        this(Utils.createSSLContext(certs));
+    }
+
+    private SSLSession getSession() {
+        return socket.getSession();
+    }
+
+    private void setEnabledCipherSuites(String... cipherSuites) {
+        socket.setEnabledCipherSuites(cipherSuites);
+    }
+
+    private void setEnabledProtocols(String... protocols) {
+        socket.setEnabledProtocols(protocols);
+    }
+
+    @SuppressWarnings(value = { "unchecked", "rawtypes" })
+    private void setServerName(String hostname) {
+        List serverNames = new ArrayList();
+        serverNames.add(createSNIHostName(hostname));
+        SSLParameters params = socket.getSSLParameters();
+        params.setServerNames(serverNames);
+        socket.setSSLParameters(params);
+    }
+
+    // Create SNIHostName via reflection due to pre-8 JDK builds don't support
+    // SNI. Those JDK builds cannot find classes SNIServerName and SNIHostName.
+    private Object createSNIHostName(String hostname) {
+        try {
+            Class<?> clazz = Class.forName("javax.net.ssl.SNIHostName");
+            return clazz.getConstructor(String.class).newInstance(hostname);
+        } catch (Exception e) {
+            throw new RuntimeException("Creates SNIHostName failed!", e);
+        }
+    }
+
+    private void setApplicationProtocols(String... protocols) {
+        SSLParameters params = socket.getSSLParameters();
+        params.setApplicationProtocols(protocols);
+        socket.setSSLParameters(params);
+    }
+
+    private String getNegotiatedApplicationProtocol() {
+        return socket.getApplicationProtocol();
+    }
+
+    private void oneTimeConnect(String host, int port) throws IOException {
+        socket.connect(new InetSocketAddress(host, port));
+
+        OutputStream out = socket.getOutputStream();
+        out.write('C');
+        out.flush();
+
+        InputStream in = socket.getInputStream();
+        in.read();
+    }
+
+    public void close() throws IOException {
+        socket.close();
+    }
+
+    public static void main(String[] args) throws IOException {
+        System.out.println("----- Client start -----");
+        int port = Integer.valueOf(System.getProperty(Utils.PROP_PORT));
+
+        String protocol = System.getProperty(Utils.PROP_PROTOCOL);
+        String cipherSuite = System.getProperty(Utils.PROP_CIPHER_SUITE);
+        String serverName = System.getProperty(Utils.PROP_SERVER_NAME);
+        String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
+        boolean supportsSNIOnServer
+                = Boolean.getBoolean(Utils.PROP_SUPPORTS_SNI_ON_SERVER);
+        boolean supportsSNIOnClient
+                = Boolean.getBoolean(Utils.PROP_SUPPORTS_SNI_ON_CLIENT);
+        boolean supportsALPNOnServer
+                = Boolean.getBoolean(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
+        boolean supportsALPNOnClient
+                = Boolean.getBoolean(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT);
+        boolean negativeCase
+                = Boolean.getBoolean(Utils.PROP_NEGATIVE_CASE_ON_CLIENT);
+        System.out.println(Utils.join(Utils.PARAM_DELIMITER,
+                "ClientJDK=" + System.getProperty(Utils.PROP_CLIENT_JDK),
+                "Protocol=" + protocol,
+                "CipherSuite=" + cipherSuite,
+                "ServerName=" + serverName,
+                "AppProtocols=" + appProtocols));
+
+        Status status = Status.SUCCESS;
+        Client client = null;
+        try {
+            client = new Client(Cert.getCerts(CipherSuite.cipherSuite(cipherSuite)));
+            client.setEnabledProtocols(protocol);
+            client.setEnabledCipherSuites(cipherSuite);
+
+            if (serverName != null) {
+                if (supportsSNIOnClient) {
+                    client.setServerName(serverName);
+                } else {
+                    System.out.println(
+                            "Ignored due to client doesn't support SNI.");
+                }
+            }
+
+            if (appProtocols != null) {
+                if (supportsALPNOnClient) {
+                    client.setApplicationProtocols(
+                            Utils.split(appProtocols, Utils.VALUE_DELIMITER));
+                } else {
+                    System.out.println(
+                            "Ignored due to client doesn't support ALPN.");
+                }
+            }
+
+            client.oneTimeConnect("localhost", port);
+
+            if (serverName != null && supportsSNIOnServer
+                    && supportsSNIOnClient) {
+                X509Certificate cert
+                        = (X509Certificate) client.getSession().getPeerCertificates()[0];
+                String subject
+                        = cert.getSubjectX500Principal().getName();
+                if (!subject.contains(serverName)) {
+                    System.out.println("Unexpected server: " + subject);
+                    status = Status.FAIL;
+                }
+            }
+
+            if (appProtocols != null && supportsALPNOnServer
+                    && supportsALPNOnClient) {
+                String negoAppProtocol
+                        = client.getNegotiatedApplicationProtocol();
+                String expectedNegoAppProtocol
+                        = System.getProperty(Utils.PROP_NEGO_APP_PROTOCOL);
+                if (!expectedNegoAppProtocol.equals(negoAppProtocol)) {
+                    System.out.println("Unexpected negotiated app protocol: "
+                            + negoAppProtocol);
+                    status = Status.FAIL;
+                }
+            }
+
+            if (status != Status.FAIL) {
+                status = negativeCase
+                       ? Status.UNEXPECTED_SUCCESS
+                       : Status.SUCCESS;
+            }
+        } catch (Exception exception) {
+            status = Utils.handleException(exception, negativeCase);
+        } finally {
+            if (client != null) {
+                client.close();
+            }
+        }
+
+        System.out.println("STATUS: " + status);
+        System.out.println("----- Client end -----");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/ClientHelloProcessing.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8210918 8210334 8209916
+ * @summary Add test to exercise server-side client hello processing
+ * @run main/othervm ClientHelloProcessing noPskNoKexModes
+ * @run main/othervm ClientHelloProcessing noPskYesKexModes
+ * @run main/othervm ClientHelloProcessing yesPskNoKexModes
+ * @run main/othervm ClientHelloProcessing yesPskYesKexModes
+ * @run main/othervm ClientHelloProcessing supGroupsSect163k1
+ */
+
+/*
+ * SunJSSE does not support dynamic system properties, no way to re-use
+ * system properties in samevm/agentvm mode.
+ */
+
+import java.io.FileInputStream;
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Objects;
+
+/*
+ * If you wish to add test cases, the following must be done:
+ * 1. Add a @run line with the parameter being a name for the test case
+ * 2. Create the ClientHello as a byte[].  It should be a complete TLS
+ *    record, but does not need upper layer headers like TCP, IP, Ethernet, etc.
+ * 3. Create a new TestCase instance, see "noPskNoKexModes" as an example
+ * 4. Create a mapping between the test case name in your @run line and the
+ *    TestCase object you created in step #3.  Add this to TESTMAP.
+ */
+
+public class ClientHelloProcessing {
+
+    private static final ByteBuffer SERVOUTBUF =
+            ByteBuffer.wrap("Server Side".getBytes());
+
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private static TrustManagerFactory trustMgrFac = null;
+    private static KeyManagerFactory keyMgrFac = null;
+
+    // Canned client hello messages
+    // These were created from packet captures using openssl 1.1.1's
+    // s_client utility.  The captured TLS record containing the client
+    // hello was then manually edited to remove or add fields if the s_client
+    // utility could not be used to generate a message with the desired
+    // extensions.  When manually altering the hello messages, care must
+    // be taken to change the lengths of the extensions themselves, the
+    // extensions vector length, the handshake message length, and the TLS
+    // record length.
+
+    // Client Hello with the pre_shared_key and psk_key_exchange_modes
+    // both absent.  Required manual removal of the psk_key_exchange_modes
+    // extension.  Similarly formed Client Hello messages may be generated
+    // by clients that don't support pre-shared keys.
+    //
+    //    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
+    //        Content Type: Handshake (22)
+    //        Version: TLS 1.0 (0x0301)
+    //        Length: 256
+    //        Handshake Protocol: Client Hello
+    //            Handshake Type: Client Hello (1)
+    //            Length: 252
+    //            Version: TLS 1.2 (0x0303)
+    //            Random: 9b796ad0cbd559fb48fc4ba32da5bb8c1ef9a7da85231860...
+    //            Session ID Length: 32
+    //            Session ID: fe8411205bc99a506952f5c28569facb96ff0f37621be072...
+    //            Cipher Suites Length: 8
+    //            Cipher Suites (4 suites)
+    //            Compression Methods Length: 1
+    //            Compression Methods (1 method)
+    //            Extensions Length: 171
+    //            Extension: server_name (len=14)
+    //            Extension: ec_point_formats (len=4)
+    //            Extension: supported_groups (len=4)
+    //            Extension: SessionTicket TLS (len=0)
+    //            Extension: status_request (len=5)
+    //            Extension: encrypt_then_mac (len=0)
+    //            Extension: extended_master_secret (len=0)
+    //            Extension: signature_algorithms (len=30)
+    //            Extension: supported_versions (len=3)
+    //            Extension: key_share (len=71)
+    private static final byte[] CLIHELLO_NOPSK_NOPSKEXMODE = {
+        22,    3,    1,    1,    0,    1,    0,    0,
+        -4,    3,    3, -101,  121,  106,  -48,  -53,
+       -43,   89,   -5,   72,   -4,   75,  -93,   45,
+       -91,  -69, -116,   30,   -7,  -89,  -38, -123,
+        35,   24,   96,   29,  -93,  -22,   10,  -97,
+       -15,  -11,    3,   32,   -2, -124,   17,   32,
+        91,  -55, -102,   80,  105,   82,  -11,  -62,
+      -123,  105,   -6,  -53, -106,   -1,   15,   55,
+        98,   27,  -32,  114, -126,  -13,   42, -104,
+      -102,   37,  -65,   52,    0,    8,   19,    2,
+        19,    3,   19,    1,    0,   -1,    1,    0,
+         0,  -85,    0,    0,    0,   14,    0,   12,
+         0,    0,    9,  108,  111,   99,   97,  108,
+       104,  111,  115,  116,    0,   11,    0,    4,
+         3,    0,    1,    2,    0,   10,    0,    4,
+         0,    2,    0,   23,    0,   35,    0,    0,
+         0,    5,    0,    5,    1,    0,    0,    0,
+         0,    0,   22,    0,    0,    0,   23,    0,
+         0,    0,   13,    0,   30,    0,   28,    4,
+         3,    5,    3,    6,    3,    8,    7,    8,
+         8,    8,    9,    8,   10,    8,   11,    8,
+         4,    8,    5,    8,    6,    4,    1,    5,
+         1,    6,    1,    0,   43,    0,    3,    2,
+         3,    4,    0,   51,    0,   71,    0,   69,
+         0,   23,    0,   65,    4,  125,  -92,  -50,
+       -91,  -39,  -55, -114,    0,   22,    2,  -50,
+       123, -126,    0,  -94,  100, -119, -106,  125,
+       -81,  -24,   51,  -84,   25,   25, -115,   13,
+       -17,  -20,   93,   68,  -97,  -79,  -98,   91,
+        86,   91, -114,  123,  119,  -87,  -12,   32,
+        63,  -41,   50,  126,  -70,   96,   33,   -6,
+        94,   -7,  -68,   54,  -47,   53,    0,   88,
+        40,  -48, -102,  -50,   88
+    };
+
+    // Client Hello with the pre_shared_key extension absent but
+    // containing the psk_key_exchange_modes extension asserted.  No
+    // manual modification was necessary.
+    //
+    //    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
+    //        Content Type: Handshake (22)
+    //        Version: TLS 1.0 (0x0301)
+    //        Length: 262
+    //        Handshake Protocol: Client Hello
+    //            Handshake Type: Client Hello (1)
+    //            Length: 258
+    //            Version: TLS 1.2 (0x0303)
+    //            Random: 9b796ad0cbd559fb48fc4ba32da5bb8c1ef9a7da85231860...
+    //            Session ID Length: 32
+    //            Session ID: fe8411205bc99a506952f5c28569facb96ff0f37621be072...
+    //            Cipher Suites Length: 8
+    //            Cipher Suites (4 suites)
+    //            Compression Methods Length: 1
+    //            Compression Methods (1 method)
+    //            Extensions Length: 177
+    //            Extension: server_name (len=14)
+    //            Extension: ec_point_formats (len=4)
+    //            Extension: supported_groups (len=4)
+    //            Extension: SessionTicket TLS (len=0)
+    //            Extension: status_request (len=5)
+    //            Extension: encrypt_then_mac (len=0)
+    //            Extension: extended_master_secret (len=0)
+    //            Extension: signature_algorithms (len=30)
+    //            Extension: supported_versions (len=3)
+    //            Extension: psk_key_exchange_modes (len=2)
+    //                Type: psk_key_exchange_modes (45)
+    //                Length: 2
+    //                PSK Key Exchange Modes Length: 1
+    //                PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
+    //            Extension: key_share (len=71)
+    private static final byte[] CLIHELLO_NOPSK_YESPSKEXMODE = {
+        22,    3,    1,    1,    6,    1,    0,    1,
+         2,    3,    3, -101,  121,  106,  -48,  -53,
+       -43,   89,   -5,   72,   -4,   75,  -93,   45,
+       -91,  -69, -116,   30,   -7,  -89,  -38, -123,
+        35,   24,   96,   29,  -93,  -22,   10,  -97,
+       -15,  -11,    3,   32,   -2, -124,   17,   32,
+        91,  -55, -102,   80,  105,   82,  -11,  -62,
+      -123,  105,   -6,  -53, -106,   -1,   15,   55,
+        98,   27,  -32,  114, -126,  -13,   42, -104,
+      -102,   37,  -65,   52,    0,    8,   19,    2,
+        19,    3,   19,    1,    0,   -1,    1,    0,
+         0,  -79,    0,    0,    0,   14,    0,   12,
+         0,    0,    9,  108,  111,   99,   97,  108,
+       104,  111,  115,  116,    0,   11,    0,    4,
+         3,    0,    1,    2,    0,   10,    0,    4,
+         0,    2,    0,   23,    0,   35,    0,    0,
+         0,    5,    0,    5,    1,    0,    0,    0,
+         0,    0,   22,    0,    0,    0,   23,    0,
+         0,    0,   13,    0,   30,    0,   28,    4,
+         3,    5,    3,    6,    3,    8,    7,    8,
+         8,    8,    9,    8,   10,    8,   11,    8,
+         4,    8,    5,    8,    6,    4,    1,    5,
+         1,    6,    1,    0,   43,    0,    3,    2,
+         3,    4,    0,   45,    0,    2,    1,    1,
+         0,   51,    0,   71,    0,   69,    0,   23,
+         0,   65,    4,  125,  -92,  -50,  -91,  -39,
+       -55, -114,    0,   22,    2,  -50,  123, -126,
+         0,  -94,  100, -119, -106,  125,  -81,  -24,
+        51,  -84,   25,   25, -115,   13,  -17,  -20,
+        93,   68,  -97,  -79,  -98,   91,   86,   91,
+      -114,  123,  119,  -87,  -12,   32,   63,  -41,
+        50,  126,  -70,   96,   33,   -6,   94,   -7,
+       -68,   54,  -47,   53,    0,   88,   40,  -48,
+      -102,  -50,   88
+    };
+
+    // Client Hello with pre_shared_key asserted and psk_key_exchange_modes
+    // absent.  This is a violation of RFC 8446.  This required manual
+    // removal of the psk_key_exchange_modes extension.
+    //
+    //    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
+    //        Content Type: Handshake (22)
+    //        Version: TLS 1.0 (0x0301)
+    //        Length: 318
+    //        Handshake Protocol: Client Hello
+    //            Handshake Type: Client Hello (1)
+    //            Length: 314
+    //            Version: TLS 1.2 (0x0303)
+    //            Random: e730e42336a19ed9fdb42919c65769132e9e779a797f188c...
+    //            Session ID Length: 32
+    //            Session ID: 6c6ed31408042fabd0c47fdeee6d19de2d6795e37590f00e...
+    //            Cipher Suites Length: 8
+    //            Cipher Suites (4 suites)
+    //            Compression Methods Length: 1
+    //            Compression Methods (1 method)
+    //            Extensions Length: 233
+    //            Extension: server_name (len=14)
+    //            Extension: ec_point_formats (len=4)
+    //            Extension: supported_groups (len=4)
+    //            Extension: SessionTicket TLS (len=0)
+    //            Extension: status_request (len=5)
+    //            Extension: encrypt_then_mac (len=0)
+    //            Extension: extended_master_secret (len=0)
+    //            Extension: signature_algorithms (len=30)
+    //            Extension: supported_versions (len=3)
+    //            Extension: key_share (len=71)
+    //            Extension: pre_shared_key (len=58)
+    //                Type: pre_shared_key (41)
+    //                Length: 58
+    //                Pre-Shared Key extension
+    //                    Identities Length: 21
+    //                    PSK Identity (length: 15)
+    //                        Identity Length: 15
+    //                        Identity: 436c69656e745f6964656e74697479
+    //                        Obfuscated Ticket Age: 0
+    //                    PSK Binders length: 33
+    //                    PSK Binders
+    private static final byte[] CLIHELLO_YESPSK_NOPSKEXMODE = {
+        22,    3,    1,    1,   62,    1,    0,    1,
+        58,    3,    3,  -25,   48,  -28,   35,   54,
+       -95,  -98,  -39,   -3,  -76,   41,   25,  -58,
+        87,  105,   19,   46,  -98,  119, -102,  121,
+       127,   24, -116,   -9,  -99,   22,  116,  -97,
+        90,   73,  -18,   32,  108,  110,  -45,   20,
+         8,    4,   47,  -85,  -48,  -60,  127,  -34,
+       -18,  109,   25,  -34,   45,  103, -107,  -29,
+       117, -112,  -16,   14,   -5,  -24,   24,   61,
+        -9,   28, -119,  -73,    0,    8,   19,    2,
+        19,    3,   19,    1,    0,   -1,    1,    0,
+         0,  -23,    0,    0,    0,   14,    0,   12,
+         0,    0,    9,  108,  111,   99,   97,  108,
+       104,  111,  115,  116,    0,   11,    0,    4,
+         3,    0,    1,    2,    0,   10,    0,    4,
+         0,    2,    0,   23,    0,   35,    0,    0,
+         0,    5,    0,    5,    1,    0,    0,    0,
+         0,    0,   22,    0,    0,    0,   23,    0,
+         0,    0,   13,    0,   30,    0,   28,    4,
+         3,    5,    3,    6,    3,    8,    7,    8,
+         8,    8,    9,    8,   10,    8,   11,    8,
+         4,    8,    5,    8,    6,    4,    1,    5,
+         1,    6,    1,    0,   43,    0,    3,    2,
+         3,    4,    0,   51,    0,   71,    0,   69,
+         0,   23,    0,   65,    4,   -6,  101,  105,
+        -2,   -6,   85,  -99,  -37,  112,   90,   44,
+      -123, -107,    4,  -12,  -64,   92,   40,  100,
+        22,  -53, -124,   54,   56,  102,   25,   76,
+       -86,   -1,    6,  110,   95,   92,  -86,  -35,
+      -101,  115,   85,   99,   19,    6,  -43,  105,
+       -37,  -92,   53,  -97,   84,   -1,  -53,   87,
+       -53, -107,  -13,  -14,   32,  101,  -35,   39,
+       102,  -17, -119,  -25,  -51,    0,   41,    0,
+        58,    0,   21,    0,   15,   67,  108,  105,
+       101,  110,  116,   95,  105,  100,  101,  110,
+       116,  105,  116,  121,    0,    0,    0,    0,
+         0,   33,   32, -113,  -27,  -44,  -71,  -68,
+       -26,  -47,   57,  -82,  -29,  -13,  -61,   77,
+        52,  -60,   27,   74, -120, -104,  102,   21,
+       121,    0,   48,   43,  -40,  -19,  -67,   57,
+       -20,   97,   23
+    };
+
+    // Client Hello containing both pre_shared_key and psk_key_exchange_modes
+    // extensions.  Generation of this hello was done by adding
+    // "-psk a1b2c3d4" to the s_client command.
+    //
+    //    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
+    //        Content Type: Handshake (22)
+    //        Version: TLS 1.0 (0x0301)
+    //        Length: 324
+    //        Handshake Protocol: Client Hello
+    //            Handshake Type: Client Hello (1)
+    //            Length: 320
+    //            Version: TLS 1.2 (0x0303)
+    //            Random: e730e42336a19ed9fdb42919c65769132e9e779a797f188c...
+    //            Session ID Length: 32
+    //            Session ID: 6c6ed31408042fabd0c47fdeee6d19de2d6795e37590f00e...
+    //            Cipher Suites Length: 8
+    //            Cipher Suites (4 suites)
+    //            Compression Methods Length: 1
+    //            Compression Methods (1 method)
+    //            Extensions Length: 239
+    //            Extension: server_name (len=14)
+    //            Extension: ec_point_formats (len=4)
+    //            Extension: supported_groups (len=4)
+    //            Extension: SessionTicket TLS (len=0)
+    //            Extension: status_request (len=5)
+    //            Extension: encrypt_then_mac (len=0)
+    //            Extension: extended_master_secret (len=0)
+    //            Extension: signature_algorithms (len=30)
+    //            Extension: supported_versions (len=3)
+    //            Extension: psk_key_exchange_modes (len=2)
+    //                Type: psk_key_exchange_modes (45)
+    //                Length: 2
+    //                PSK Key Exchange Modes Length: 1
+    //                PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)
+    //            Extension: key_share (len=71)
+    //            Extension: pre_shared_key (len=58)
+    //                Type: pre_shared_key (41)
+    //                Length: 58
+    //                Pre-Shared Key extension
+    //                    Identities Length: 21
+    //                    PSK Identity (length: 15)
+    //                        Identity Length: 15
+    //                        Identity: 436c69656e745f6964656e74697479
+    //                        Obfuscated Ticket Age: 0
+    //                    PSK Binders length: 33
+    //                    PSK Binders
+    private static final byte[] CLIHELLO_YESPSK_YESPSKEXMODE = {
+        22,    3,    1,    1,   68,    1,    0,    1,
+        64,    3,    3,  -25,   48,  -28,   35,   54,
+       -95,  -98,  -39,   -3,  -76,   41,   25,  -58,
+        87,  105,   19,   46,  -98,  119, -102,  121,
+       127,   24, -116,   -9,  -99,   22,  116,  -97,
+        90,   73,  -18,   32,  108,  110,  -45,   20,
+         8,    4,   47,  -85,  -48,  -60,  127,  -34,
+       -18,  109,   25,  -34,   45,  103, -107,  -29,
+       117, -112,  -16,   14,   -5,  -24,   24,   61,
+        -9,   28, -119,  -73,    0,    8,   19,    2,
+        19,    3,   19,    1,    0,   -1,    1,    0,
+         0,  -17,    0,    0,    0,   14,    0,   12,
+         0,    0,    9,  108,  111,   99,   97,  108,
+       104,  111,  115,  116,    0,   11,    0,    4,
+         3,    0,    1,    2,    0,   10,    0,    4,
+         0,    2,    0,   23,    0,   35,    0,    0,
+         0,    5,    0,    5,    1,    0,    0,    0,
+         0,    0,   22,    0,    0,    0,   23,    0,
+         0,    0,   13,    0,   30,    0,   28,    4,
+         3,    5,    3,    6,    3,    8,    7,    8,
+         8,    8,    9,    8,   10,    8,   11,    8,
+         4,    8,    5,    8,    6,    4,    1,    5,
+         1,    6,    1,    0,   43,    0,    3,    2,
+         3,    4,    0,   45,    0,    2,    1,    1,
+         0,   51,    0,   71,    0,   69,    0,   23,
+         0,   65,    4,   -6,  101,  105,   -2,   -6,
+        85,  -99,  -37,  112,   90,   44, -123, -107,
+         4,  -12,  -64,   92,   40,  100,   22,  -53,
+      -124,   54,   56,  102,   25,   76,  -86,   -1,
+         6,  110,   95,   92,  -86,  -35, -101,  115,
+        85,   99,   19,    6,  -43,  105,  -37,  -92,
+        53,  -97,   84,   -1,  -53,   87,  -53, -107,
+       -13,  -14,   32,  101,  -35,   39,  102,  -17,
+      -119,  -25,  -51,    0,   41,    0,   58,    0,
+        21,    0,   15,   67,  108,  105,  101,  110,
+       116,   95,  105,  100,  101,  110,  116,  105,
+       116,  121,    0,    0,    0,    0,    0,   33,
+        32, -113,  -27,  -44,  -71,  -68,  -26,  -47,
+        57,  -82,  -29,  -13,  -61,   77,   52,  -60,
+        27,   74, -120, -104,  102,   21,  121,    0,
+        48,   43,  -40,  -19,  -67,   57,  -20,   97,
+        23
+    };
+
+    // Client Hello with sect163k1 and secp256r1 as supported groups.  This
+    // test covers an error condition where a known, supported curve that is
+    // not in the default enabled set of curves would cause failures.
+    // Generation of this hello was done using "-curves sect163k1:prime256v1"
+    // as an option to s_client.
+    //
+    //    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
+    //        Content Type: Handshake (22)
+    //        Version: TLS 1.0 (0x0301)
+    //        Length: 210
+    //        Handshake Protocol: Client Hello
+    //            Handshake Type: Client Hello (1)
+    //            Length: 206
+    //            Version: TLS 1.2 (0x0303)
+    //            Random: 05cbae9b834851d856355b72601cb67b7cd4eb51f29ed50b...
+    //            Session ID Length: 0
+    //            Cipher Suites Length: 56
+    //            Cipher Suites (28 suites)
+    //            Compression Methods Length: 1
+    //            Compression Methods (1 method)
+    //            Extensions Length: 109
+    //            Extension: server_name (len=14)
+    //            Extension: ec_point_formats (len=4)
+    //            Extension: supported_groups (len=6)
+    //                Type: supported_groups (10)
+    //                Length: 6
+    //                Supported Groups List Length: 4
+    //                Supported Groups (2 groups)
+    //                    Supported Group: sect163k1 (0x0001)
+    //                    Supported Group: secp256r1 (0x0017)
+    //            Extension: SessionTicket TLS (len=0)
+    //            Extension: status_request (len=5)
+    //            Extension: encrypt_then_mac (len=0)
+    //            Extension: extended_master_secret (len=0)
+    //            Extension: signature_algorithms (len=48)
+    private static final byte[] CLIHELLO_SUPGRP_SECT163K1 = {
+        22,    3,    1,    0,  -46,    1,    0,    0,
+       -50,    3,    3,    5,  -53,  -82, -101, -125,
+        72,   81,  -40,   86,   53,   91,  114,   96,
+        28,  -74,  123,  124,  -44,  -21,   81,  -14,
+       -98,  -43,   11,   90,  -87, -106,   13,   63,
+       -62,  100,  111,    0,    0,   56,  -64,   44,
+       -64,   48,    0,  -97,  -52,  -87,  -52,  -88,
+       -52,  -86,  -64,   43,  -64,   47,    0,  -98,
+       -64,   36,  -64,   40,    0,  107,  -64,   35,
+       -64,   39,    0,  103,  -64,   10,  -64,   20,
+         0,   57,  -64,    9,  -64,   19,    0,   51,
+         0,  -99,    0, -100,    0,   61,    0,   60,
+         0,   53,    0,   47,    0,   -1,    1,    0,
+         0,  109,    0,    0,    0,   14,    0,   12,
+         0,    0,    9,  108,  111,   99,   97,  108,
+       104,  111,  115,  116,    0,   11,    0,    4,
+         3,    0,    1,    2,    0,   10,    0,    6,
+         0,    4,    0,    1,    0,   23,    0,   35,
+         0,    0,    0,    5,    0,    5,    1,    0,
+         0,    0,    0,    0,   22,    0,    0,    0,
+        23,    0,    0,    0,   13,    0,   48,    0,
+        46,    4,    3,    5,    3,    6,    3,    8,
+         7,    8,    8,    8,    9,    8,   10,    8,
+        11,    8,    4,    8,    5,    8,    6,    4,
+         1,    5,    1,    6,    1,    3,    3,    2,
+         3,    3,    1,    2,    1,    3,    2,    2,
+         2,    4,    2,    5,    2,    6,    2
+    };
+
+    public static interface TestCase {
+        void execTest() throws Exception;
+    }
+
+    private static final Map<String, TestCase> TESTMAP = new HashMap<>();
+
+    public static void main(String[] args) throws Exception {
+        boolean allGood = true;
+        System.setProperty("javax.net.debug", "ssl:handshake");
+        trustMgrFac = makeTrustManagerFactory(trustFilename, passwd);
+        keyMgrFac = makeKeyManagerFactory(keyFilename, passwd);
+
+        // Populate the test map
+        TESTMAP.put("noPskNoKexModes", noPskNoKexModes);
+        TESTMAP.put("noPskYesKexModes", noPskYesKexModes);
+        TESTMAP.put("yesPskNoKexModes", yesPskNoKexModes);
+        TESTMAP.put("yesPskYesKexModes", yesPskYesKexModes);
+        TESTMAP.put("supGroupsSect163k1", supGroupsSect163k1);
+
+        if (args == null || args.length < 1) {
+            throw new Exception("FAIL: Test @run line is missing a test label");
+        }
+
+        // Pull the test to run from the test map.
+        TestCase test = Objects.requireNonNull(TESTMAP.get(args[0]),
+                "No TestCase found for test label " + args[0]);
+        test.execTest();
+    }
+
+    /**
+     * Test case to cover hellos with no pre_shared_key nor
+     * psk_key_exchange_modes extensions.  Clients not supporting PSK at all
+     * may send hellos like this.
+     */
+    private static final TestCase noPskNoKexModes = new TestCase() {
+        @Override
+        public void execTest() throws Exception {
+            System.out.println("\nTest: PSK = No, PSKEX = No");
+            processClientHello("TLS", CLIHELLO_NOPSK_NOPSKEXMODE);
+            System.out.println("PASS");
+        }
+    };
+
+    /**
+     * Test case to cover hellos with no pre_shared_key but have the
+     * psk_key_exchange_modes extension.  This kind of hello is seen from
+     * some popular browsers and test clients.
+     */
+    private static final TestCase noPskYesKexModes = new TestCase() {
+        @Override
+        public void execTest() throws Exception {
+            System.out.println("\nTest: PSK = No, PSKEX = Yes");
+            processClientHello("TLS", CLIHELLO_NOPSK_YESPSKEXMODE);
+            System.out.println("PASS");
+        }
+    };
+
+    /**
+     * Test case using a client hello with the pre_shared_key extension but
+     * no psk_key_exchange_modes extension present.  This is a violation of
+     * 8446 and should cause an exception when unwrapped and processed by
+     * SSLEngine.
+     */
+    private static final TestCase yesPskNoKexModes = new TestCase() {
+        @Override
+        public void execTest() throws Exception {
+            try {
+                System.out.println("\nTest: PSK = Yes, PSKEX = No");
+                processClientHello("TLS", CLIHELLO_YESPSK_NOPSKEXMODE);
+                throw new Exception(
+                    "FAIL: Client Hello processed without expected error");
+            } catch (SSLHandshakeException sslhe) {
+                System.out.println("PASS: Caught expected exception: " + sslhe);
+            }
+        }
+    };
+
+    /**
+     * Test case using a client hello asserting the pre_shared_key and
+     * psk_key_exchange_modes extensions.
+     */
+    private static final TestCase yesPskYesKexModes = new TestCase() {
+        @Override
+        public void execTest() throws Exception {
+            System.out.println("\nTest: PSK = Yes, PSKEX = Yes");
+            processClientHello("TLS", CLIHELLO_YESPSK_YESPSKEXMODE);
+            System.out.println("PASS");
+        }
+    };
+
+    /**
+     * Test case with a client hello asserting two named curves in the
+     * supported_groups extension: sect163k1 and secp256r1.
+     */
+    private static final TestCase supGroupsSect163k1 = new TestCase() {
+        @Override
+        public void execTest() throws Exception {
+            System.out.println("\nTest: Use of non-default-enabled " +
+                    "Supported Group (sect163k1)");
+            processClientHello("TLS", CLIHELLO_SUPGRP_SECT163K1);
+            System.out.println("PASS");
+        }
+    };
+
+    /**
+     * Send a ClientHello message to an SSLEngine instance configured as a
+     * server.
+     *
+     * @param proto the protocol used to create the SSLContext.  This will
+     *      default to "TLS" if null is passed in.
+     * @param message the ClientHello as a complete TLS record.
+     *
+     * @throws Exception if any processing errors occur.  The caller (TestCase)
+     *      is expected to deal with the exception in whatever way appropriate
+     *      for the test.
+     */
+    private static void processClientHello(String proto, byte[] message)
+            throws Exception {
+        SSLEngine serverEng = makeServerEngine(proto, keyMgrFac, trustMgrFac);
+        ByteBuffer sTOc = makePacketBuf(serverEng);
+        SSLEngineResult serverResult;
+
+        ByteBuffer cTOs = ByteBuffer.wrap(message);
+        System.out.println("CLIENT-TO-SERVER\n" +
+                dumpHexBytes(cTOs, 16, "\n", " "));
+        serverResult = serverEng.unwrap(cTOs, SERVOUTBUF);
+        printResult("server unwrap: ", serverResult);
+        runDelegatedTasks(serverResult, serverEng);
+        serverEng.wrap(SERVOUTBUF, sTOc);
+    }
+
+    /**
+     * Create a TrustManagerFactory from a given keystore.
+     *
+     * @param tsPath the path to the trust store file.
+     * @param pass the password for the trust store.
+     *
+     * @return a new TrustManagerFactory built from the trust store provided.
+     *
+     * @throws GeneralSecurityException if any processing errors occur
+     *      with the Keystore instantiation or TrustManagerFactory creation.
+     * @throws IOException if any loading error with the trust store occurs.
+     */
+    private static TrustManagerFactory makeTrustManagerFactory(String tsPath,
+            String pass) throws GeneralSecurityException, IOException {
+        KeyStore ts = KeyStore.getInstance("JKS");
+        char[] passphrase = pass.toCharArray();
+
+        ts.load(new FileInputStream(tsPath), passphrase);
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+        return tmf;
+    }
+
+    /**
+     * Create a KeyManagerFactory from a given keystore.
+     *
+     * @param ksPath the path to the keystore file.
+     * @param pass the password for the keystore.
+     *
+     * @return a new TrustManagerFactory built from the keystore provided.
+     *
+     * @throws GeneralSecurityException if any processing errors occur
+     *      with the Keystore instantiation or KeyManagerFactory creation.
+     * @throws IOException if any loading error with the keystore occurs
+     */
+    private static KeyManagerFactory makeKeyManagerFactory(String ksPath,
+            String pass) throws GeneralSecurityException, IOException {
+        KeyStore ks = KeyStore.getInstance("JKS");
+        char[] passphrase = pass.toCharArray();
+
+        ks.load(new FileInputStream(ksPath), passphrase);
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+        return kmf;
+    }
+
+    /**
+     * Create an SSLEngine instance from a given protocol specifier,
+     * KeyManagerFactory and TrustManagerFactory.
+     *
+     * @param proto the protocol specifier for the SSLContext.  This will
+     *      default to "TLS" if null is provided.
+     * @param kmf an initialized KeyManagerFactory.  May be null.
+     * @param tmf an initialized TrustManagerFactory.  May be null.
+     *
+     * @return an SSLEngine instance configured as a server and with client
+     *      authentication disabled.
+     *
+     * @throws GeneralSecurityException if any errors occur during the
+     *      creation of the SSLEngine.
+     */
+    private static SSLEngine makeServerEngine(String proto,
+            KeyManagerFactory kmf, TrustManagerFactory tmf)
+            throws GeneralSecurityException {
+        SSLContext ctx = SSLContext.getInstance(proto != null ? proto : "TLS");
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        SSLEngine ssle = ctx.createSSLEngine();
+        ssle.setUseClientMode(false);
+        ssle.setNeedClientAuth(false);
+        return ssle;
+    }
+
+    /**
+     * Make a ByteBuffer sized for TLS records that can be used by an SSLEngine.
+     *
+     * @param engine the SSLEngine used to determine the packet buffer size.
+     *
+     * @return a ByteBuffer sized for TLS packets.
+     */
+    private static ByteBuffer makePacketBuf(SSLEngine engine) {
+        SSLSession sess = engine.getSession();
+        ByteBuffer packetBuf = ByteBuffer.allocate(sess.getPacketBufferSize());
+        return packetBuf;
+    }
+
+    /**
+     * Runs any delegated tasks after unwrapping TLS records.
+     *
+     * @param result the most recent result from an unwrap operation on
+     *      an SSLEngine.
+     * @param engine the SSLEngine used to unwrap the data.
+     *
+     * @throws Exception if any errors occur while running the delegated
+     *      tasks.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        if (hsStatus == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                System.out.println("\trunning delegated task...");
+                runnable.run();
+            }
+            hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            System.out.println("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    /**
+     * Display the results of a wrap or unwrap operation from an SSLEngine.
+     *
+     * @param str a label to be prefixed to the result display.
+     * @param result the result returned from the wrap/unwrap operation.
+     */
+    private static void printResult(String str, SSLEngineResult result) {
+        System.out.println("The format of the SSLEngineResult is: \n" +
+            "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+            "\t\"bytesConsumed() / bytesProduced()\"\n");
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        System.out.println(str + result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() + " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            System.out.println("\t...ready for application data");
+        }
+    }
+
+    /**
+     * Dump the hex bytes of a buffer into string form.
+     *
+     * @param data The array of bytes to dump to stdout.
+     * @param itemsPerLine The number of bytes to display per line
+     *      if the {@code lineDelim} character is blank then all bytes
+     *      will be printed on a single line.
+     * @param lineDelim The delimiter between lines
+     * @param itemDelim The delimiter between bytes
+     *
+     * @return The hexdump of the byte array
+     */
+    private static String dumpHexBytes(byte[] data, int itemsPerLine,
+            String lineDelim, String itemDelim) {
+        return dumpHexBytes(ByteBuffer.wrap(data), itemsPerLine, lineDelim,
+                itemDelim);
+    }
+
+    /**
+     * Dump the hex bytes of a buffer into string form.
+     *
+     * @param data The ByteBuffer to dump to stdout.
+     * @param itemsPerLine The number of bytes to display per line
+     *      if the {@code lineDelim} character is blank then all bytes
+     *      will be printed on a single line.
+     * @param lineDelim The delimiter between lines
+     * @param itemDelim The delimiter between bytes
+     *
+     * @return The hexdump of the byte array
+     */
+    private static String dumpHexBytes(ByteBuffer data, int itemsPerLine,
+            String lineDelim, String itemDelim) {
+        StringBuilder sb = new StringBuilder();
+        if (data != null) {
+            data.mark();
+            int i = 0;
+            while (data.remaining() > 0) {
+                if (i % itemsPerLine == 0 && i != 0) {
+                    sb.append(lineDelim);
+                }
+                sb.append(String.format("%02X", data.get())).append(itemDelim);
+                i++;
+            }
+            data.reset();
+        }
+
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/Compatibility.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary This test is used to check the interop compatibility on JSSE among
+ *     different JDK releases.
+ *     Note that, this is a manual test. For more details about the test and
+ *     its usages, please look through README.
+ *
+ * @library /test/lib ../TLSCommon
+ * @compile -source 1.6 -target 1.6 JdkUtils.java Server.java Client.java
+ * @run main/manual Compatibility
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import jdk.test.lib.process.OutputAnalyzer;
+
+public class Compatibility {
+
+    protected List<UseCase> getUseCases() {
+        return UseCase.getAllUseCases();
+    }
+
+    protected Set<JdkInfo> getJdkInfos() {
+        return jdkInfoList();
+    }
+
+    protected List<TestCase> runTest() throws Exception {
+        Set<JdkInfo> jdkInfos = getJdkInfos();
+
+        List<TestCase> testCases = new ArrayList<>();
+        ExecutorService executor = Executors.newCachedThreadPool();
+        PrintStream origStdOut = System.out;
+        PrintStream origStdErr = System.err;
+
+        boolean debug = Boolean.getBoolean("debug");
+
+        String securityPropertiesFile = System.getProperty(
+                "test.security.properties",
+                System.getProperty("test.src") + "/java.security");
+        System.out.println("security properties: " + securityPropertiesFile);
+
+        // If true, server and client CANNOT be a same JDK
+        boolean disallowSameEndpoint = Boolean.getBoolean("disallowSameEndpoint");
+        System.out.println("disallowSameEndpoint: " + disallowSameEndpoint);
+
+        try (PrintStream printStream = new PrintStream(
+                new FileOutputStream(Utils.TEST_LOG, true))) {
+            System.setOut(printStream);
+            System.setErr(printStream);
+
+            System.out.println(Utils.startHtml());
+            System.out.println(Utils.startPre());
+
+            for (UseCase useCase : getUseCases()) {
+                for (JdkInfo serverJdk : jdkInfos) {
+                    Map<String, String> props = new LinkedHashMap<>();
+                    if (debug) {
+                        props.put("javax.net.debug", "all");
+                    }
+                    props.put("java.security.properties", securityPropertiesFile);
+
+                    props.put(Utils.PROP_PROTOCOL, useCase.protocol.name);
+                    props.put(Utils.PROP_CIPHER_SUITE, useCase.cipherSuite.name());
+                    props.put(Utils.PROP_CLIENT_AUTH, String.valueOf(useCase.clientAuth));
+                    if (useCase.appProtocol != UseCase.AppProtocol.NONE) {
+                        props.put(Utils.PROP_APP_PROTOCOLS,
+                                Utils.join(Utils.VALUE_DELIMITER,
+                                        useCase.appProtocol.appProtocols));
+                        props.put(Utils.PROP_NEGO_APP_PROTOCOL,
+                                useCase.appProtocol.negoAppProtocol);
+                    }
+                    props.put(Utils.PROP_SERVER_JDK, serverJdk.version);
+
+                    props.put(Utils.PROP_SUPPORTS_SNI_ON_SERVER,
+                            serverJdk.supportsSNI + "");
+                    props.put(Utils.PROP_SUPPORTS_ALPN_ON_SERVER,
+                            serverJdk.supportsALPN + "");
+
+                    for (JdkInfo clientJdk : jdkInfos) {
+                        if (disallowSameEndpoint && clientJdk == serverJdk) {
+                            continue;
+                        }
+
+                        TestCase testCase = new TestCase(serverJdk, clientJdk,
+                                useCase);
+                        System.out.println(Utils.anchorName(testCase.toString(),
+                                "===== Case start ====="));
+                        System.out.println(testCase.toString());
+
+                        props.put(Utils.PROP_NEGATIVE_CASE_ON_SERVER,
+                                testCase.negativeCaseOnServer + "");
+                        props.put(Utils.PROP_NEGATIVE_CASE_ON_CLIENT,
+                                testCase.negativeCaseOnClient + "");
+
+                        Future<OutputAnalyzer> serverFuture = executor.submit(() -> {
+                            return runServer(serverJdk.jdkPath, props);
+                        });
+                        int port = waitForServerStarted();
+                        System.out.println("port=" + port);
+
+                        props.put(Utils.PROP_PORT, port + "");
+
+                        props.put(Utils.PROP_CLIENT_JDK, clientJdk.version);
+
+                        props.put(Utils.PROP_SUPPORTS_SNI_ON_CLIENT,
+                                clientJdk.supportsSNI + "");
+                        props.put(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT,
+                                clientJdk.supportsALPN + "");
+                        if (useCase.serverName != UseCase.ServerName.NONE) {
+                            props.put(Utils.PROP_SERVER_NAME,
+                                    useCase.serverName.name);
+                        }
+
+                        Status clientStatus = null;
+                        if (port != -1) {
+                            String clientOutput = runClient(clientJdk.jdkPath,
+                                    props).getOutput();
+                            clientStatus = getStatus(clientOutput);
+                        }
+
+                        String serverOutput = serverFuture.get().getOutput();
+                        Status serverStatus = getStatus(serverOutput);
+                        testCase.setStatus(caseStatus(serverStatus, clientStatus));
+                        testCases.add(testCase);
+                        System.out.printf(
+                                "ServerStatus=%s, ClientStatus=%s, CaseStatus=%s%n",
+                                serverStatus, clientStatus, testCase.getStatus());
+
+                        System.out.println("===== Case end =====");
+                    }
+                }
+            }
+
+            System.out.println(Utils.endPre());
+            System.out.println(Utils.endHtml());
+        }
+        System.setOut(origStdOut);
+        System.setErr(origStdErr);
+        executor.shutdown();
+
+        return testCases;
+    }
+
+    // Generates the test result report.
+    protected boolean generateReport(List<TestCase> testCases)
+            throws IOException {
+        boolean failed = false;
+        StringBuilder report = new StringBuilder();
+        report.append(Utils.startHtml());
+        report.append(Utils.tableStyle());
+        report.append(Utils.startTable());
+        report.append(Utils.row(
+                "No.",
+                "ServerJDK",
+                "ClientJDK",
+                "Protocol",
+                "CipherSuite",
+                "ClientAuth",
+                "SNI",
+                "ALPN",
+                "Status"));
+        for (int i = 0, size = testCases.size(); i < size; i++) {
+            TestCase testCase = testCases.get(i);
+
+            report.append(Utils.row(
+                    Utils.anchorLink(
+                            Utils.TEST_LOG,
+                            testCase.toString(),
+                            i + ""),
+                    testCase.serverJdk.version,
+                    testCase.clientJdk.version,
+                    testCase.useCase.protocol.name,
+                    testCase.useCase.cipherSuite,
+                    Utils.boolToStr(
+                            testCase.useCase.clientAuth),
+                    Utils.boolToStr(
+                            testCase.useCase.serverName == UseCase.ServerName.EXAMPLE),
+                    Utils.boolToStr(
+                            testCase.useCase.appProtocol == UseCase.AppProtocol.EXAMPLE),
+                    testCase.getStatus()));
+            failed = failed
+                    || testCase.getStatus() == Status.FAIL
+                    || testCase.getStatus() == Status.UNEXPECTED_SUCCESS;
+        }
+        report.append(Utils.endTable());
+        report.append(Utils.endHtml());
+
+        generateFile("report.html", report.toString());
+        return failed;
+    }
+
+    protected void run() throws Exception {
+        System.out.println("Test start");
+        List<TestCase> testCases= runTest();
+        System.out.println("Test end");
+
+        boolean failed = generateReport(testCases);
+        System.out.println("Report was generated.");
+
+        if (failed) {
+            throw new RuntimeException("At least one case failed. "
+                    + "Please check logs for more details.");
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        new Compatibility().run();;
+    }
+
+    private static Status getStatus(String log) {
+        if (log.contains(Status.UNEXPECTED_SUCCESS.name())) {
+            return Status.UNEXPECTED_SUCCESS;
+        } else if (log.contains(Status.SUCCESS.name())) {
+            return Status.SUCCESS;
+        } else if (log.contains(Status.EXPECTED_FAIL.name())) {
+            return Status.EXPECTED_FAIL;
+        } else if (log.contains(Status.TIMEOUT.name())) {
+            return Status.TIMEOUT;
+        } else {
+            return Status.FAIL;
+        }
+    }
+
+    private static Status caseStatus(Status serverStatus, Status clientStatus) {
+        if (clientStatus == null || clientStatus == Status.TIMEOUT) {
+            return serverStatus == Status.EXPECTED_FAIL
+                   ? Status.EXPECTED_FAIL
+                   : Status.FAIL;
+        } else if (serverStatus == Status.TIMEOUT) {
+            return clientStatus == Status.EXPECTED_FAIL
+                   ? Status.EXPECTED_FAIL
+                   : Status.FAIL;
+        } else {
+            return serverStatus == clientStatus
+                   ? serverStatus
+                   : Status.FAIL;
+        }
+    }
+
+    // Retrieves JDK info from the file which is specified by jdkListFile.
+    // And the current testing JDK, which is specified by test.jdk, always be used.
+    private static Set<JdkInfo> jdkInfoList() {
+        List<String> jdkList = jdkList();
+        jdkList.add(System.getProperty("test.jdk"));
+
+        Set<JdkInfo> jdkInfoList = new LinkedHashSet<>();
+        for (String jdkPath : jdkList) {
+            JdkInfo jdkInfo = new JdkInfo(jdkPath);
+            // JDK version must be unique.
+            if (!jdkInfoList.add(jdkInfo)) {
+                System.out.println("The JDK version is duplicate: " + jdkPath);
+            }
+        }
+        return jdkInfoList;
+    }
+
+    private static List<String> jdkList() {
+        String listFile = System.getProperty("jdkListFile");
+        System.out.println("jdk list file: " + listFile);
+        if (listFile != null && Files.exists(Paths.get(listFile))) {
+            try (Stream<String> lines = Files.lines(Paths.get(listFile))) {
+                return lines.filter(line -> {
+                    return !line.trim().isEmpty();
+                }).collect(Collectors.toList());
+            } catch (IOException e) {
+                throw new RuntimeException("Cannot get jdk list", e);
+            }
+        } else {
+            return new ArrayList<>();
+        }
+    }
+
+    // Checks if server is already launched, and returns server port.
+    private static int waitForServerStarted()
+            throws IOException, InterruptedException {
+        System.out.print("Waiting for server");
+        long deadline = System.currentTimeMillis() + Utils.TIMEOUT;
+        int port;
+        while ((port = getServerPort()) == -1
+                && System.currentTimeMillis() < deadline) {
+            System.out.print(".");
+            TimeUnit.SECONDS.sleep(1);
+        }
+        System.out.println();
+
+        return port;
+    }
+
+    // Retrieves the latest server port from port.log.
+    private static int getServerPort() throws IOException {
+        if (!Files.exists(Paths.get(Utils.PORT_LOG))) {
+            return -1;
+        }
+
+        try (Stream<String> lines = Files.lines(Paths.get(Utils.PORT_LOG))) {
+            return Integer.valueOf(lines.findFirst().get());
+        }
+    }
+
+    private static OutputAnalyzer runServer(String jdkPath,
+            Map<String, String> props) {
+        return ProcessUtils.java(jdkPath, props, Server.class);
+    }
+
+    private static OutputAnalyzer runClient(String jdkPath,
+            Map<String, String> props) {
+        return ProcessUtils.java(jdkPath, props, Client.class);
+    }
+
+    private static void generateFile(String path, String content)
+            throws IOException {
+        try(FileWriter writer = new FileWriter(new File(path))) {
+            writer.write(content);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/JdkInfo.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * It represents a JDK with some specific attributes.
+ * If two JdkInfo instances have the same version value, the instances are
+ * regarded as equivalent.
+ */
+public class JdkInfo {
+
+    public final String jdkPath;
+
+    public final String version;
+    public final String supportedProtocols;
+    public final String supportedCipherSuites;
+    public final boolean supportsSNI;
+    public final boolean supportsALPN;
+
+    public JdkInfo(String jdkPath) {
+        this.jdkPath = jdkPath;
+
+        String output = jdkAttributes(jdkPath);
+        if (output == null || output.trim().isEmpty()) {
+            throw new RuntimeException(
+                    "Cannot determine the JDK attributes: " + jdkPath);
+        }
+
+        String[] attributes = Utils.split(output, Utils.PARAM_DELIMITER);
+        version = attributes[0].replaceAll(".*=", "");
+        supportedProtocols = attributes[1].replaceAll(".*=", "");
+        supportedCipherSuites = attributes[2].replaceAll(".*=", "");
+        supportsSNI = Boolean.valueOf(attributes[3].replaceAll(".*=", ""));
+        supportsALPN = Boolean.valueOf(attributes[4].replaceAll(".*=", ""));
+    }
+
+    // Determines the specific attributes for the specified JDK.
+    private static String jdkAttributes(String jdkPath) {
+        return ProcessUtils.java(jdkPath, null, JdkUtils.class).getOutput();
+    }
+
+    @Override
+    public int hashCode() {
+        return version == null ? 0 : version.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        JdkInfo other = (JdkInfo) obj;
+        if (version == null) {
+            if (other.version != null) {
+                return false;
+            }
+        } else if (!version.equals(other.version)) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean supportsProtocol(Protocol protocol) {
+        return supportedProtocols.contains(protocol.name);
+    }
+
+    public boolean supportsCipherSuite(CipherSuite cipherSuite) {
+        return supportedCipherSuites.contains(cipherSuite.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/JdkRelease.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * JDK major versions.
+ */
+public enum JdkRelease {
+
+    JDK6(6, "1.6"),
+    JDK7(7, "1.7"),
+    JDK8(8, "1.8"),
+    JDK9(9, "9"),
+    JDK10(10, "10"),
+    JDK11(11, "11");
+
+    public final int sequence;
+    public final String release;
+
+    private JdkRelease(int sequence, String release) {
+        this.sequence = sequence;
+        this.release = release;
+    }
+
+    public static JdkRelease getRelease(String jdkVersion) {
+        if (jdkVersion.startsWith(JDK6.release)) {
+            return JDK6;
+        } else if (jdkVersion.startsWith(JDK7.release)) {
+            return JDK7;
+        } else if (jdkVersion.startsWith(JDK8.release)) {
+            return JDK8;
+        } else if (jdkVersion.startsWith(JDK9.release)) {
+            return JDK9;
+        } else if (jdkVersion.startsWith(JDK10.release)) {
+            return JDK10;
+        } else if (jdkVersion.startsWith(JDK11.release)) {
+            return JDK11;
+        }
+
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/JdkUtils.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+import java.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocketFactory;
+
+/*
+ * This class is used for returning some specific JDK information.
+ */
+public class JdkUtils {
+
+    public static final String JAVA_RUNTIME_VERSION = "javaRuntimeVersion";
+    public static final String SUPPORTED_PROTOCOLS = "supportedProtocols";
+    public static final String SUPPORTED_CIPHER_SUITES = "supportedCipherSuites";
+    public static final String SUPPORTS_SNI = "supportsSNI";
+    public static final String SUPPORTS_ALPN = "supportsALPN";
+
+    // Returns the JDK build version.
+    public static String javaRuntimeVersion() {
+        return System.getProperty("java.runtime.version");
+    }
+
+    private static String supportedProtocols() {
+        StringBuilder protocols = new StringBuilder();
+        for (String protocol : new String[] {
+                "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3" }) {
+            if (supportsProtocol(protocol)) {
+                protocols.append(protocol).append(Utils.VALUE_DELIMITER);
+            }
+        }
+        return protocols.toString().substring(
+                0, protocols.toString().length() - 1);
+    }
+
+    private static boolean supportsProtocol(String protocol) {
+        boolean supported = true;
+        try {
+            SSLContext.getInstance(protocol);
+        } catch (NoSuchAlgorithmException e) {
+            supported = false;
+        }
+        return supported;
+    }
+
+    private static String supportedCipherSuites() {
+        StringBuilder cipherSuites = new StringBuilder();
+        String[] supportedCipherSuites = ((SSLSocketFactory) SSLSocketFactory
+                .getDefault()).getSupportedCipherSuites();
+        for (int i = 0; i < supportedCipherSuites.length - 1; i++) {
+            cipherSuites.append(supportedCipherSuites[i])
+                    .append(Utils.VALUE_DELIMITER);
+        }
+        cipherSuites.append(
+                supportedCipherSuites[supportedCipherSuites.length - 1]);
+        return cipherSuites.toString();
+    }
+
+    // Checks if SNI is supported by the JDK build.
+    private static boolean supportsSNI() {
+        boolean isSupported = true;
+        try {
+            SSLParameters.class.getMethod("getServerNames");
+        } catch (NoSuchMethodException e) {
+            isSupported = false;
+        }
+        return isSupported;
+    }
+
+    // Checks if ALPN is supported by the JDK build.
+    private static boolean supportsALPN() {
+        boolean isSupported = true;
+        try {
+            SSLParameters.class.getMethod("getApplicationProtocols");
+        } catch (NoSuchMethodException e) {
+            isSupported = false;
+        }
+        return isSupported;
+    }
+
+    public static void main(String[] args) throws NoSuchAlgorithmException {
+        System.out.print(Utils.join(Utils.PARAM_DELIMITER,
+                attr(JAVA_RUNTIME_VERSION, javaRuntimeVersion()),
+                attr(SUPPORTED_PROTOCOLS, supportedProtocols()),
+                attr(SUPPORTED_CIPHER_SUITES, supportedCipherSuites()),
+                attr(SUPPORTS_SNI, supportsSNI()),
+                attr(SUPPORTS_ALPN, supportsALPN())));
+    }
+
+    private static String attr(String name, Object value) {
+        return name + "=" + String.valueOf(value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/ProcessUtils.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * Utilities for executing java process.
+ */
+public class ProcessUtils {
+
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+    public static OutputAnalyzer java(String jdkPath, Map<String, String> props,
+            Class<?> clazz) {
+        List<String> cmds = new ArrayList<>();
+        cmds.add(jdkPath + "/bin/java");
+
+        if (props != null) {
+            for (Map.Entry<String, String> prop : props.entrySet()) {
+                cmds.add("-D" + prop.getKey() + "=" + prop.getValue());
+            }
+        }
+
+        cmds.add("-cp");
+        cmds.add(TEST_CLASSES);
+        cmds.add(clazz.getName());
+        try {
+            return ProcessTools.executeCommand(
+                    cmds.toArray(new String[cmds.size()]));
+        } catch (Throwable e) {
+            throw new RuntimeException("Execute command failed: " + cmds, e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/README	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,130 @@
+# Copyright (c) 2017, 2019, 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.
+#
+# 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.
+
+##### Summary #####
+This test is used to check the interop compatibility on JSSE among different
+JDK releases. The oldest version supported by the test is JDK 7. Some of Java
+source files, JdkUtils.java, Server.java, and Client.java, use only JDK 7-compliant
+language features and APIs, in order to allowing different JDK releases can load
+and run associated classes.
+
+##### Output #####
+The test can generate a report at $JTREG_WORKDIR/scratch/report.html to display
+the key information for each case. It also outputs all of details on both of
+server and client sides to a separated file at $JTREG_WORKDIR/scratch/test.html.
+
+##### Report Columns #####
+No.
+    A sequence number. It contains a hyper link to the corresponding details
+    in $JTREG_WORKDIR/scratch/test.html.
+
+ServerJDK
+    The version of the JDK that acts as server.
+
+ClientJDK
+    The version of the JDK that acts as client.
+
+Protocol
+    The TLS protocol version.
+
+CipherSuite
+    The only enabled cipher suite on both of server and client.
+
+ClientAuth
+    If the client authentication is checked, the value is "Y"; otherwise, "N".
+
+SNI
+    If the SNI is checked, the value is "Y"; otherwise, "N".
+
+ALPN
+    If the ALPN is checked, the value is "Y"; otherwise, "N".
+
+Status
+    It indicates the communication status for a test case.
+    There are three status:
+    SUCCESS: Communication succeed as expected.
+    UNEXPECTED_SUCCESS: Communication succeed as unexpected.
+    FAIL: Communication fails with unexpected failure.
+    EXPECTED_FAIL: Communication fails with expected failure.
+    Please note that, if a case finishes as status UNEXPECTED_SUCCESS or FAIL,
+    that means the case fails. Any failed case results in the test goes to fail.
+
+##### Usage #####
+jtreg [-options] \
+    [-Ddebug=<true|false>] \
+    [-DfullCases=<true|false>] \
+    [-DfullCipherSuites=<true|false>] \
+    [-DjdkListFile=</path/to/jdkListFile>] \
+    $JDK_WORKSPACE/test/jdk/javax/net/ssl/compatibility/Compatibility.java
+
+Besides the common jtreg options, like -jdk, this test introduces some more
+properties:
+debug
+    It indicates if the test enable -Djavax.net.debug=all. This is a boolean
+    property, and the default value is false.
+    It is not mandatory.
+
+fullCases
+    It indicates if testing the full or mandatory set of parameter values.
+    Every parameter provides a mandatory value set that must be covered.
+    For more details about the parameter value sets, please see Parameter.java.
+    This is a boolean property, and the default value is false.
+    It is not mandatory.
+
+fullCipherSuites
+    It indicates if testing the full or mandatory set of cipher suites.
+    For more details about the specific cipher suite sets, see CipherSuite in
+    Parameter.java.
+    This is a boolean property, and the default value is false.
+    It is not mandatory.
+
+jdkListFile
+    It indicate the path of a file, which lists the absolute paths of different
+    JDK builds. If no this property, the current testing JDK, specified by JTREG
+    option -jdk, is used as the testing JDK.
+    It is not mandatory.
+
+##### Usage Examples #####
+Example 1
+$ jtreg -jdk:/path/to/latest/jdk \
+    $JDK_WS/jdk/test/javax/net/ssl/compatibility/Compatibility.java
+This example doesn't specify any property introduced by the test. That means
+it uses the current testing JDK, namely /path/to/latest/jdk, as server and
+client. It doesn't output any debug log, and tests only mandatory parameter
+value sets.
+
+Example 2
+$ cat /path/to/jdkList
+/path/to/jdk6
+/path/to/jdk7
+/path/to/jdk8
+/path/to/jdk9
+/path/to/jdk10
+
+$ jtreg -jdk:/path/to/latest/jdk \
+    -Ddebug=true \
+    -DfullCipherSuites=true \
+    -DjdkListFile=/path/to/jdkList \
+    $JDK_WS/jdk/test/javax/net/ssl/compatibility/Compatibility.java
+The above example uses a file "/path/to/jdkList" to contain the paths of local
+different JDK builds through 6 to 10. The execution uses each of JDK builds as
+server and client respectively. And it enables SSL debug flag, and tests the
+full parameter value set.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/Server.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+
+/*
+ * A simple SSL socket server.
+ */
+public class Server {
+
+    private final SSLServerSocket serverSocket;
+
+    public Server(SSLContext context, int port) throws Exception {
+        SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
+        serverSocket = (SSLServerSocket) serverFactory.createServerSocket(port);
+        serverSocket.setSoTimeout(Utils.TIMEOUT);
+    }
+
+    public Server(Cert[] certs, int port) throws Exception {
+        this(Utils.createSSLContext(certs), port);
+    }
+
+    public Server(Cert[] certs) throws Exception {
+        this(certs, 0);
+    }
+
+    private void setEnabledCipherSuites(String... cipherSuites) {
+        serverSocket.setEnabledCipherSuites(cipherSuites);
+    }
+
+    private void setEnabledProtocols(String... protocols) {
+        serverSocket.setEnabledProtocols(protocols);
+    }
+
+    private void setNeedClientAuth(boolean needClientAuth) {
+        serverSocket.setNeedClientAuth(needClientAuth);
+    }
+
+    private void setApplicationProtocols(String... protocols) {
+        SSLParameters params = serverSocket.getSSLParameters();
+        params.setApplicationProtocols(protocols);
+        serverSocket.setSSLParameters(params);
+    }
+
+    public int getPort() {
+        return serverSocket.getLocalPort();
+    }
+
+    private void accept() throws IOException {
+        SSLSocket socket = null;
+        try {
+            socket = (SSLSocket) serverSocket.accept();
+
+            InputStream in = socket.getInputStream();
+            in.read();
+
+            OutputStream out = socket.getOutputStream();
+            out.write('S');
+            out.flush();
+        } finally {
+            if (socket != null) {
+                socket.close();
+            }
+        }
+    }
+
+    public void close() throws IOException {
+        serverSocket.close();
+    }
+
+    public static void main(String[] args) throws IOException {
+        System.out.println("----- Server start -----");
+        String protocol = System.getProperty(Utils.PROP_PROTOCOL);
+        String cipherSuite = System.getProperty(Utils.PROP_CIPHER_SUITE);
+        boolean clientAuth
+                = Boolean.getBoolean(Utils.PROP_CLIENT_AUTH);
+        String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
+        boolean supportsALPN
+                = Boolean.getBoolean(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
+        boolean negativeCase
+                = Boolean.getBoolean(Utils.PROP_NEGATIVE_CASE_ON_SERVER);
+
+        System.out.println(Utils.join(Utils.PARAM_DELIMITER,
+                "ServerJDK=" + System.getProperty(Utils.PROP_SERVER_JDK),
+                "Protocol=" + protocol,
+                "CipherSuite=" + cipherSuite,
+                "ClientAuth=" + clientAuth,
+                "AppProtocols=" + appProtocols));
+
+        Status status = Status.SUCCESS;
+        Server server = null;
+        try {
+            server = new Server(Cert.getCerts(CipherSuite.cipherSuite(cipherSuite)));
+            System.out.println("port=" + server.getPort());
+            server.setNeedClientAuth(clientAuth);
+            server.setEnabledProtocols(protocol);
+            server.setEnabledCipherSuites(cipherSuite);
+            if (appProtocols != null) {
+                if (supportsALPN) {
+                    server.setApplicationProtocols(
+                            Utils.split(appProtocols, Utils.VALUE_DELIMITER));
+                } else {
+                    System.out.println(
+                            "Ignored due to server doesn't support ALPN.");
+                }
+            }
+
+            savePort(server.getPort());
+            server.accept();
+
+            status = negativeCase ? Status.UNEXPECTED_SUCCESS : Status.SUCCESS;
+        } catch (Exception exception) {
+            status = Utils.handleException(exception, negativeCase);
+        } finally {
+            if (server != null) {
+                server.close();
+            }
+
+            deletePortFile();
+        }
+
+        System.out.println("STATUS: " + status);
+        System.out.println("----- Server end -----");
+    }
+
+    private static void deletePortFile() {
+        File portFile = new File(Utils.PORT_LOG);
+        if (portFile.exists() && !portFile.delete()) {
+            throw new RuntimeException("Cannot delete port log");
+        }
+    }
+
+    private static void savePort(int port) throws IOException {
+        FileWriter writer = null;
+        try {
+            writer = new FileWriter(new File(Utils.PORT_LOG));
+            writer.write(port + "");
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/Status.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+/*
+ * Test case result status.
+ */
+public enum Status {
+
+    SUCCESS, UNEXPECTED_SUCCESS, FAIL, EXPECTED_FAIL, TIMEOUT;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/TestCase.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+/*
+ * A test case for a specific TLS communication use case between two JDKs.
+ */
+public class TestCase {
+
+    public final JdkInfo serverJdk;
+    public final JdkInfo clientJdk;
+    public final UseCase useCase;
+
+    public final boolean negativeCaseOnServer;
+    public final boolean negativeCaseOnClient;
+
+    private Status status;
+
+    public TestCase(JdkInfo serverJdk, JdkInfo clientJdk, UseCase useCase) {
+        this.serverJdk = serverJdk;
+        this.clientJdk = clientJdk;
+        this.useCase = useCase;
+
+        negativeCaseOnServer = useCase.negativeCase
+                || !serverJdk.supportsCipherSuite(useCase.cipherSuite);
+        negativeCaseOnClient = useCase.negativeCase
+                || !clientJdk.supportsCipherSuite(useCase.cipherSuite);
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.join(Utils.PARAM_DELIMITER,
+                "ServerJDK=" + serverJdk.version,
+                "ClientJDK=" + clientJdk.version,
+                useCase.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/UseCase.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * The TLS communication use case.
+ */
+public class UseCase {
+
+    private static final boolean FULL_CASES
+            = Boolean.getBoolean("fullCases");
+
+    public static final boolean FULL_CIPHER_SUITES
+            = Boolean.getBoolean("fullCipherSuites");
+
+    public static final Protocol[] PROTOCOLS = new Protocol[] {
+            Protocol.TLSV1,
+            Protocol.TLSV1_1,
+            Protocol.TLSV1_2,
+            Protocol.TLSV1_3 };
+
+    public static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] {
+            CipherSuite.TLS_AES_128_GCM_SHA256,
+            CipherSuite.TLS_AES_256_GCM_SHA384,
+            CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
+            CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+            CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
+            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+            CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
+            CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+            CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
+            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+            CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
+            CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 };
+
+    public static final CipherSuite[] MANDATORY_CIPHER_SUITES = new CipherSuite[] {
+            CipherSuite.TLS_AES_128_GCM_SHA256,
+            CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
+            CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 };
+
+    enum ServerName {
+
+        NONE(null),
+        EXAMPLE("EXAMPLE");
+
+        final String name;
+
+        private ServerName(String name) {
+            this.name = name;
+        }
+    }
+
+    enum AppProtocol {
+
+        NONE(null, null),
+        EXAMPLE(new String[] { Utils.HTTP_2, Utils.HTTP_1_1 }, Utils.HTTP_2);
+
+        final String[] appProtocols;
+
+        // Expected negotiated application protocol
+        final String negoAppProtocol;
+
+        private AppProtocol(String[] appProtocols, String negoAppProtocol) {
+            this.appProtocols = appProtocols;
+            this.negoAppProtocol = negoAppProtocol;
+        }
+    }
+
+    private static final Object[][] PARAMS = new Object[][] {
+            PROTOCOLS,
+            FULL_CASES ? CIPHER_SUITES : MANDATORY_CIPHER_SUITES,
+            FULL_CASES ? new Boolean[] { false, true } : new Boolean[] { true },
+            FULL_CASES
+                    ? new ServerName[] { ServerName.NONE, ServerName.EXAMPLE }
+                    : new ServerName[] { ServerName.EXAMPLE },
+            FULL_CASES
+                    ? new AppProtocol[] {
+                            AppProtocol.NONE,
+                            AppProtocol.EXAMPLE }
+                    : new AppProtocol[] {
+                            AppProtocol.EXAMPLE } };
+
+    public final Protocol protocol;
+    public final CipherSuite cipherSuite;
+    public final Boolean clientAuth;
+    public final ServerName serverName;
+    public final AppProtocol appProtocol;
+
+    public final boolean negativeCase;
+
+    public UseCase(
+            Protocol protocol,
+            CipherSuite cipherSuite,
+            boolean clientAuth,
+            ServerName serverName,
+            AppProtocol appProtocol) {
+        this.protocol = protocol;
+        this.cipherSuite = cipherSuite;
+        this.clientAuth = clientAuth;
+        this.serverName = serverName;
+        this.appProtocol = appProtocol;
+
+        negativeCase = !cipherSuite.supportedByProtocol(protocol);
+    }
+
+    @Override
+    public String toString() {
+        return Utils.join(Utils.PARAM_DELIMITER,
+                "Protocol=" + protocol.name,
+                "CipherSuite=" + cipherSuite,
+                "ClientAuth=" + clientAuth,
+                "ServerName=" + serverName,
+                "AppProtocols=" + appProtocol);
+    }
+
+    public static List<UseCase> getAllUseCases() {
+        List<UseCase> useCases = new ArrayList<>();
+        getUseCases(PARAMS, 0, new Object[PARAMS.length], useCases);
+        return useCases;
+    }
+
+    private static void getUseCases(Object[][] params, int index,
+            Object[] currentValues, List<UseCase> useCases) {
+        if (index == params.length) {
+            Protocol protocol = (Protocol) currentValues[0];
+            CipherSuite cipherSuite = (CipherSuite) currentValues[1];
+
+            UseCase useCase = new UseCase(
+                    protocol,
+                    cipherSuite,
+                    (Boolean) currentValues[2],
+                    (ServerName) currentValues[3],
+                    (AppProtocol) currentValues[4]);
+            useCases.add(useCase);
+        } else {
+            Object[] values = params[index];
+            for (int i = 0; i < values.length; i++) {
+                currentValues[index] = values[i];
+                getUseCases(params, index + 1, currentValues, useCases);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/Utils.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2017, 2019, 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.
+ *
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManagerFactory;
+
+/*
+ * Utilities for testing.
+ */
+public class Utils {
+
+    /* ***** Properties ***** */
+    public static final String PROP_PORT = "test.port";
+    public static final String PROP_PROTOCOL = "test.protocol";
+    public static final String PROP_CIPHER_SUITE = "test.cipher.suite";
+    public static final String PROP_CLIENT_AUTH = "test.client.auth";
+    public static final String PROP_SERVER_JDK = "test.server.jdk";
+    public static final String PROP_CLIENT_JDK = "test.client.jdk";
+    public static final String PROP_SERVER_NAME = "test.server.name";
+    public static final String PROP_APP_PROTOCOLS
+            = "test.app.protocols";
+    public static final String PROP_NEGO_APP_PROTOCOL
+            = "test.negotiated.app.protocol";
+    public static final String PROP_SUPPORTS_SNI_ON_SERVER
+            = "test.supports.sni.on.server";
+    public static final String PROP_SUPPORTS_SNI_ON_CLIENT
+            = "test.supports.sni.on.client";
+    public static final String PROP_SUPPORTS_ALPN_ON_SERVER
+            = "test.supports.alpn.on.server";
+    public static final String PROP_SUPPORTS_ALPN_ON_CLIENT
+            = "test.supports.alpn.on.client";
+    public static final String PROP_NEGATIVE_CASE_ON_SERVER
+            = "test.negative.case.on.server";
+    public static final String PROP_NEGATIVE_CASE_ON_CLIENT
+            = "test.negative.case.on.client";
+
+    public static final int TIMEOUT = 10000;
+    public static final char[] PASSWORD = "testpass".toCharArray();
+
+    public static final String TEST_LOG = "test.html";
+    public static final String PORT_LOG = "port";
+
+    public static final String HTTP_2 = "h2";
+    public static final String HTTP_1_1 = "http/1.1";
+
+    public static final String PARAM_DELIMITER = ";";
+    public static final String VALUE_DELIMITER = ",";
+
+    /*
+     * Creates SSL context with the specified certificate.
+     */
+    public static SSLContext createSSLContext(Cert... certs) throws Exception {
+        KeyStore trustStore = KeyStore.getInstance("JKS");
+        trustStore.load(null, null);
+        for (int i = 0; i < certs.length; i++) {
+            trustStore.setCertificateEntry("trust-" + certs[i].name(),
+                    createCert(certs[i]));
+        }
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(trustStore);
+
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        keyStore.load(null, null);
+        for (int i = 0; i < certs.length; i++) {
+            PrivateKey privKey = createKey(certs[i]);
+            keyStore.setKeyEntry("cert-" + certs[i].name(), privKey, PASSWORD,
+                    new Certificate[] { createCert(certs[i]) });
+        }
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(keyStore, PASSWORD);
+
+        SSLContext context = SSLContext.getInstance("TLS");
+        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        return context;
+    }
+
+    private static Certificate createCert(Cert cert) throws IOException {
+        try {
+            CertificateFactory certFactory
+                    = CertificateFactory.getInstance("X.509");
+            return certFactory.generateCertificate(
+                    new ByteArrayInputStream(cert.certMaterials.getBytes()));
+        } catch (Exception e) {
+            throw new RuntimeException("Create key failed: " + cert, e);
+        }
+    }
+
+    private static PrivateKey createKey(Cert cert)
+            throws NoSuchAlgorithmException, InvalidKeySpecException {
+        PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
+                hexToBytes(cert.privKeyMaterials));
+        KeyFactory keyFactory = KeyFactory.getInstance(
+                cert.keyAlgorithm.name);
+        PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
+        return privKey;
+    }
+
+    public static byte[] hexToBytes(String hex) {
+        if (hex == null) {
+            return null;
+        }
+
+        int length = hex.length();
+        if (length % 2 != 0) {
+            throw new IllegalArgumentException("Hex format is wrong.");
+        }
+
+        byte[] bytes = new byte[length / 2];
+        for (int i = 0; i < length; i += 2) {
+            bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+                    + Character.digit(hex.charAt(i + 1), 16));
+        }
+        return bytes;
+    }
+
+    public static String join(String delimiter, String... values) {
+        StringBuilder result = new StringBuilder();
+        if (values != null && values.length > 0) {
+            for (int i = 0; i < values.length - 1; i++) {
+                result.append(values[i]).append(delimiter);
+            }
+            result.append(values[values.length - 1]);
+        }
+        return result.toString();
+    }
+
+    public static String[] split(String str, String delimiter) {
+        return str == null ? new String[0] : str.split(delimiter);
+    }
+
+    public static String boolToStr(boolean bool) {
+        return bool ? "Y" : "N";
+    }
+
+    public static Status handleException(Exception exception,
+            boolean negativeCase) {
+        Status status;
+        if ((exception instanceof SSLHandshakeException
+                || exception instanceof IllegalArgumentException)
+                && negativeCase) {
+            System.out.println("Expected exception: " + exception);
+            status = Status.EXPECTED_FAIL;
+        } else if (exception instanceof SocketTimeoutException) {
+            status = Status.TIMEOUT;
+        } else {
+            exception.printStackTrace(System.out);
+            status = Status.FAIL;
+        }
+        return status;
+    }
+
+    /* The HTML-related constants and methods. */
+
+    private static final String STYLE
+            = "style=\"font-family: Courier New; "
+            + "font-size: 12px; "
+            + "white-space: pre-wrap\"";
+
+    private static final String TABLE_STYLE
+            = "#test { font-family: \"Courier New\"; font-size: 12px; border-collapse: collapse; }\n"
+            + "#test td { border: 1px solid #ddd; padding: 4px; }\n"
+            + "#test tr:nth-child(odd) { background-color: #f2f2f2; }";
+
+    public static String row(Object... values) {
+        StringBuilder row = new StringBuilder();
+        row.append(startTr());
+        for (Object value : values) {
+            row.append(startTd());
+            row.append(value);
+            row.append(endTd());
+        }
+        row.append(endTr());
+        return row.toString();
+    }
+
+    public static String startHtml() {
+        return startTag("html");
+    }
+
+    public static String endHtml() {
+        return endTag("html");
+    }
+
+    public static String startPre() {
+        return startTag("pre " + STYLE);
+    }
+
+    public static String endPre() {
+        return endTag("pre");
+    }
+
+    public static String anchorName(String name, String text) {
+        return "<a name=" + name + ">" + text + "</a>";
+    }
+
+    public static String anchorLink(String file, String anchorName,
+            String text) {
+        return "<a href=" + file + "#" + anchorName + ">" + text + "</a>";
+    }
+
+    public static String tableStyle() {
+        return startTag("style") + TABLE_STYLE  +endTag("style");
+    }
+
+    public static String startTable() {
+        return startTag("table id=\"test\"");
+    }
+
+    public static String endTable() {
+        return endTag("table");
+    }
+
+    private static String startTr() {
+        return startTag("tr");
+    }
+
+    private static String endTr() {
+        return endTag("tr");
+    }
+
+    private static String startTd() {
+        return startTag("td");
+    }
+
+    private static String endTd() {
+        return endTag("td");
+    }
+
+    private static String startTag(String tag) {
+        return "<" + tag + ">";
+    }
+
+    private static String endTag(String tag) {
+        return "</" + tag + ">";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/compatibility/java.security	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,2 @@
+jdk.certpath.disabledAlgorithms=
+jdk.tls.disabledAlgorithms=
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/etc/README	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,116 @@
+Keystores used for the JSSE regression test suite.
+
+keystore
+truststore
+==========
+
+These are the primary two keystores and contain entries for testing most
+of the JSSE regression test files.  There are three entries, one RSA-based,
+one DSA-based and one EC-based.  If they expire, simply recreate them
+using keytool and most of the test cases should work.
+
+The password on both files is:
+
+    passphrase
+
+There are no individual key entry passwords at this time.
+
+
+keystore entries
+================
+
+Alias name: dummy
+-----------------
+Creation date: May 16, 2016
+Entry type: PrivateKeyEntry
+Certificate chain length: 1
+Certificate[1]:
+Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Serial number: 57399b87
+Valid from: Mon May 16 10:06:38 UTC 2016 until: Sat May 16 10:06:38 UTC 2026
+Signature algorithm name: SHA256withRSA
+Version: 1
+
+This can be generated using hacked (update the keytool source code so that
+it can be used for version 1 X.509 certificate) keytool command:
+% keytool -genkeypair -alias dummy -keyalg RSA -keysize 2048 \
+  -sigalg SHA256withRSA \
+  -dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US" \
+  -validity 3652 -keypass passphrase -keystore keystore -storepass passphrase
+
+
+Alias name: dummyecdsa
+----------------------
+Creation date: May 16, 2016
+Entry type: PrivateKeyEntry
+Certificate chain length: 1
+Certificate[1]:
+Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Serial number: 57399c1d
+Valid from: Mon May 16 10:09:01 UTC 2016 until: Sat May 16 10:09:01 UTC 2026
+Signature algorithm name: SHA256withECDSA
+Version: 1
+
+This can be generated using hacked (update the keytool source code so that
+it can be used for version 1 X.509 certificate) keytool command:
+% keytool -genkeypair -alias dummy -keyalg EC -keysize 256 \
+  -sigalg SHA256withECDSA \
+  -dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US" \
+  -validity 3652 -keypass passphrase -keystore keystore -storepass passphrase
+
+Alias name: dummydsa
+--------------------
+Creation date: Mar 29, 2018
+Entry type: PrivateKeyEntry
+Certificate chain length: 1
+Certificate[1]:
+Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Serial number: 324d85f0
+Valid from: Thu Mar 29 16:06:34 PDT 2018 until: Tue Mar 28 16:06:34 PDT 2028
+Signature algorithm name: SHA256withDSA
+Version: 3
+
+This can be generated using hacked (update the keytool source code so that
+it can be used for version 1 X.509 certificate) keytool command:
+% keytool -genkeypair -alias dummydsa -keyalg DSA -keysize 1024 \
+  -sigalg SHA256withDSA \
+  -dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US" \
+  -validity 3652 -keypass passphrase -keystore keystore -storepass passphrase
+
+Alias name: dummyecrsa
+--------------------
+Creation date: Apr 13, 2018
+Entry type: PrivateKeyEntry
+Certificate chain length: 2
+Certificate[1]:
+Owner: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Issuer: CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US
+Serial number: 6f2d1faa
+Valid from: Fri Apr 13 16:20:55 CST 2018 until: Wed Apr 12 16:20:55 CST 2028
+Version: 3
+
+This can be generated by using keytool command:
+% keytool -genkeypair -alias dummyecrsa -keyalg EC -keysize 256 \
+  -keypass passphrase -storepass passphrase -keystore keystore \
+  -dname "CN=dummy.example.com, OU=Dummy, O=Dummy, L=Cupertino, ST=CA, C=US"
+% keytool -certreq -alias dummyecrsa -storepass passphrase -keystore keystore \
+  -file ecrsa.csr
+% keytool -gencert -alias dummy -storepass passphrase -keystore keystore \
+  -validity 3652 -infile ecrsa.csr -outfile ecrsa.cer
+% keytool -importcert -alias dummyecrsa -storepass passphrase -keystore keystore \
+  -file ecrsa.cer
+
+
+truststore entries
+==================
+This key store contains only trusted certificate entries. The same
+certificates, except dummyecrsa, are used in both keystore and truststore.
+
+
+unknown_keystore
+================
+A keystore you can use when you don't want things to be verified.
+Use this with keystore/truststore, and you'll never get a match.
Binary file test/javax/net/ssl/etc/keystore has changed
Binary file test/javax/net/ssl/etc/truststore has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/interop/ClientHelloBufferUnderflowException.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8215790 8219389
+ * @summary Verify exception
+ * @modules java.base/sun.security.util
+ * @run main/othervm ClientHelloBufferUnderflowException
+ */
+
+import sun.security.util.HexDumpEncoder;
+import javax.net.ssl.SSLHandshakeException;
+
+public class ClientHelloBufferUnderflowException extends ClientHelloInterOp {
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        try {
+            (new ClientHelloBufferUnderflowException()).run();
+        } catch (SSLHandshakeException e) {
+            System.out.println("Correct exception thrown: " + e);
+            return;
+        } catch (Exception e) {
+            System.out.println("Failed: Exception not SSLHandShakeException");
+            System.out.println(e.getMessage());
+            throw e;
+        }
+
+        throw new Exception("No expected exception");
+    }
+
+    @Override
+    protected byte[] createClientHelloMessage() {
+        // The ClientHello message in hex: 16 03 01 00 05 01 00 00 01 03
+        // Record Header:
+        // 16 - type is 0x16 (handshake record)
+        // 03 01 - protocol version is 3.1 (also known as TLS 1.0)
+        // 00 05 - 0x05 (5) bytes of handshake message follows
+        // Handshake Header:
+        // 01 - handshake message type 0x01 (client hello)
+        // 00 00 01 - 0x01 (1) bytes of client hello follows
+        // Client Version:
+        // 03 - incomplete client version
+        //
+        // (Based on https://tls.ulfheim.net)
+        byte[] bytes = {
+            0x16, 0x03, 0x01, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x03};
+
+        System.out.println("The ClientHello message used");
+        try {
+            (new HexDumpEncoder()).encodeBuffer(bytes, System.out);
+        } catch (Exception e) {
+            // ignore
+        }
+
+        return bytes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/interop/ClientHelloChromeInterOp.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2016, 2017, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8169362
+ * @summary Interop automated testing with Chrome
+ * @modules jdk.crypto.ec
+ *          java.base/sun.security.util
+ * @run main/othervm ClientHelloChromeInterOp
+ */
+
+import java.util.Base64;
+import sun.security.util.HexDumpEncoder;
+
+public class ClientHelloChromeInterOp extends ClientHelloInterOp {
+    // The ClientHello message.
+    //
+    // Captured from Chrome browser (version 54.0.2840.87 m (64-bit)) on
+    // Windows 10.
+    private final static String ClientHelloMsg =
+        "FgMBAL4BAAC6AwOWBEueOntnurZ+WAW0D9Qn2HpdzXLu0MgDjsD9e5JU6AAAIsA\n" +
+        "rwC/ALMAwzKnMqMwUzBPACcATwArAFACcAJ0ALwA1AAoBAABv/wEAAQAAAAATAB\n" +
+        "EAAA53d3cub3JhY2xlLmNvbQAXAAAAIwAAAA0AEgAQBgEGAwUBBQMEAQQDAgECA\n" +
+        "wAFAAUBAAAAAAASAAAAEAAOAAwCaDIIaHR0cC8xLjF1UAAAAAsAAgEAAAoACAAG\n" +
+        "AB0AFwAY";
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        (new ClientHelloChromeInterOp()).run();
+    }
+
+    @Override
+    protected byte[] createClientHelloMessage() {
+        byte[] bytes = Base64.getMimeDecoder().decode(ClientHelloMsg);
+
+        // Dump the hex codes of the ClientHello message so that developers
+        // can easily check whether the message is captured correct or not.
+        HexDumpEncoder dump = new HexDumpEncoder();
+        System.out.println("The ClientHello message used");
+        try {
+            dump.encodeBuffer(bytes, System.out);
+        } catch (Exception e) {
+            // ignore
+        }
+
+        return bytes;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/interop/ClientHelloInterOp.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.nio.*;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.util.Base64;
+
+public abstract class ClientHelloInterOp {
+
+    /*
+     * Certificates and keys used in the test.
+     */
+    // Trusted certificates.
+    private final static String[] trustedCertStrs = {
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: Nov  9 03:24:05 2016 GMT
+        //     Not After : Oct 20 03:24:05 2037 GMT
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICHDCCAcGgAwIBAgIJAM83C/MVp9F5MAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xNjExMDkwMzI0MDVaFw0zNzEwMjAwMzI0MDVaMDsxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
+        "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABGeQXwyeNyU4UAATfwUbMO5zaREI21Wh\n" +
+        "bds6WDu+PmfK8SWsTgsgpYxBRui+fZtYqSmbdjkurvAQ3j2fvN++BtWjga0wgaow\n" +
+        "HQYDVR0OBBYEFDF/OeJ82qBSRkAm1rdZUPbWfDzyMGsGA1UdIwRkMGKAFDF/OeJ8\n" +
+        "2qBSRkAm1rdZUPbWfDzyoT+kPTA7MQswCQYDVQQGEwJVUzENMAsGA1UEChMESmF2\n" +
+        "YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2WCCQDPNwvzFafReTAPBgNV\n" +
+        "HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqhkjOPQQDAgNJADBGAiEAlHQY\n" +
+        "QFPlODOsjLVQYSxgeSUvYzMp0vP8naeVB9bfFG8CIQCFfrKZvhq9z3bOtlYKxs2a\n" +
+        "EWUjUZ82a1JTqkP+lgHY5A==\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withRSA, 2048 bits
+        // Validity
+        //     Not Before: Nov  9 03:24:16 2016 GMT
+        //     Not After : Oct 20 03:24:16 2037 GMT
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDpzCCAo+gAwIBAgIJAJAYpR2aIlA1MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xNjExMDkwMzI0MTZaFw0zNzEwMjAwMzI0MTZaMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+F/FTPODYzsU0Pakfp\n" +
+        "lsh88YoQWZPjABhCU+HPsCTMYc8UBkaiduUzregwwVBW3D7kmec2K408krGQsxdy\n" +
+        "oKJA12GL/XX1YgzDEsyBRk/gvex5lPaBIZiJ5IZlUfjLuRDGxPjtRelBTpZ7SUet\n" +
+        "PJVZz6zV6hMPGO6kQzCtbzzET515EE0okIS40LkAmtWoOmVm3gRldomaZTrZ0V2L\n" +
+        "MMaJGzrXYqk0SX+PYul8v+2EEHeMuaXG/XpK5xsg9gZvzpKqFQcBOdENoJHB07go\n" +
+        "jCmRC328ALqr+bMyktKAuYfB+mhjmN2AU8TQx72WPpvNTXxFDYcwo+8254cCAVKB\n" +
+        "e98CAwEAAaOBrTCBqjAdBgNVHQ4EFgQUlJQlQTbi8YIyiNf+SqF7LtH+gicwawYD\n" +
+        "VR0jBGQwYoAUlJQlQTbi8YIyiNf+SqF7LtH+giehP6Q9MDsxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZjZYIJ\n" +
+        "AJAYpR2aIlA1MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3\n" +
+        "DQEBCwUAA4IBAQAI0lTY0YAKQ2VdoIQ6dnqolphLVWdNGiC9drHEYSn7+hmAD2r2\n" +
+        "v1U/9m752TkcT74a65xKbEVuVtleD/w6i+QjALW2PYt6ivjOnnY0a9Y9a9UCa00j\n" +
+        "C9415sCw84Tp9VoKtuYqzhN87bBUeABOw5dsW3z32C2N/YhprkqeF/vdx4JxulPr\n" +
+        "PKze5BREXnKLA1ISoDioCPphvNMKrSpkAofb1rTCwtgt5V/WFls283L52ORmpRGO\n" +
+        "Ja88ztXOz00ZGu0RQLwlmpN7m8tNgA/5MPrldyYIwegP4RSkkJlF/8+hxvvqfJhK\n" +
+        "FFDa0HHQSJfR2b9628Iniw1UHOMMT6qx5EHr\n" +
+        "-----END CERTIFICATE-----"
+        };
+
+    // End entity certificate.
+    private final static String[] endEntityCertStrs = {
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: Nov  9 03:24:05 2016 GMT
+        //     Not After : Jul 27 03:24:05 2036 GMT
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIB1DCCAXmgAwIBAgIJAKVa+4dIUjaLMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xNjExMDkwMzI0MDVaFw0zNjA3MjcwMzI0MDVaMFIxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEV\n" +
+        "MBMGA1UEAwwMSW50ZXJPcCBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n" +
+        "h4vXNUJzULq4e7fAOvF0WiWU6cllOAMus1GqTFvcnRPOChl8suZsvksO0CpZqL3h\n" +
+        "jXmVX9dp1FV/rUBGLo1aG6NPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSO8V5+\n" +
+        "bj0ik0T9BtJc4jLJt7m6wjAfBgNVHSMEGDAWgBQxfznifNqgUkZAJta3WVD21nw8\n" +
+        "8jAKBggqhkjOPQQDAgNJADBGAiEAk7MF+L9bFRwUsbPsBCbCqH9DMdzBQR+kFDNf\n" +
+        "lfn8Rs4CIQD9qWvBXd+EJqwraxiX6cftaFchn+T2HpvMboy+irMFow==\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withRSA, 2048 bits
+        // Validity
+        //     Not Before: Nov  9 03:24:16 2016 GMT
+        //     Not After : Jul 27 03:24:16 2036 GMT
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDczCCAlugAwIBAgIJAPhM2oUKx0aJMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xNjExMDkwMzI0MTZaFw0zNjA3MjcwMzI0MTZaMFIxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTEVMBMGA1UEAwwMSW50ZXJPcCBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
+        "MIIBCgKCAQEA36tJaXfJ2B/AFvES+tnueyQPSNABVu9nfMdU+NEPamJ+FH7cEF8Z\n" +
+        "1Spr1vlQgNzCpDUVrfnmT75rCapgz5ldA9+y+3hdfUyHjZBzzfx+6GHXLB4u6eU2\n" +
+        "NATa7vqSLNbcLcfZ7/QmkFqg4JRJbX4F42kKkRJrWdKZ8UoCYC8WXWvDaZ3nUs05\n" +
+        "XHe+mBJ8qMNPTbYST1jpzXPyH5CljlFGYi2mKJDTImDhwht7mu2+zvwvbJ81Gj2X\n" +
+        "JUSTSf9fu0zxFcCk6RmJPw9nSVqePVlOwtNNBodfKN+k4yr+gOz1v8NmMtmEtklV\n" +
+        "Sulr/J4QxI+E2Zar/C+4XjxkvstIS+PNKQIDAQABo2MwYTALBgNVHQ8EBAMCA+gw\n" +
+        "HQYDVR0OBBYEFHt19CItAz0VOF0WKGWwaT4DtEsSMB8GA1UdIwQYMBaAFJSUJUE2\n" +
+        "4vGCMojX/kqhey7R/oInMBIGA1UdEQEB/wQIMAaHBH8AAAEwDQYJKoZIhvcNAQEL\n" +
+        "BQADggEBACKYZWvo9B9IEpCCdBba2sNo4X1NI/VEY3fyUx1lkw+Kna+1d2Ab+RCZ\n" +
+        "cf3Y85fcwv03hNE///wNBp+Nde4NQRDK/oiQARzWwWslfinm5d83eQwzC3cpSzt+\n" +
+        "7ts6M5UlOblGsLXZI7THWO1tkgoEra9p+zezxLMmf/2MpNyZMZlVoJPM2YGxU9cN\n" +
+        "ws0AyeY1gpBEdT21vjsBPdxxj6qklXVMnzS3zF8YwXyOndDYQWdjmFEknRK/qmQ2\n" +
+        "gkLHrzpSpyCziecna5mGuDRdCU2dpsWiq1npEPXTq+PQGwWYcoaFTtXF8DDqhfPC\n" +
+        "4Abe8gPm6MfzerdmS3RFTj9b/DIIENM=\n" +
+        "-----END CERTIFICATE-----"
+        };
+
+    // Private key in the format of PKCS#8.
+    private final static String[] endEntityPrivateKeys = {
+        //
+        // EC private key related to cert endEntityCertStrs[0].
+        //
+        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgA3pmS+OrIjGyUv2F\n" +
+        "K/PkyayJIePM2RTFYxNoQqmJGnihRANCAASHi9c1QnNQurh7t8A68XRaJZTpyWU4\n" +
+        "Ay6zUapMW9ydE84KGXyy5my+Sw7QKlmoveGNeZVf12nUVX+tQEYujVob",
+
+        //
+        // RSA private key related to cert endEntityCertStrs[1].
+        //
+        "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfq0lpd8nYH8AW\n" +
+        "8RL62e57JA9I0AFW72d8x1T40Q9qYn4UftwQXxnVKmvW+VCA3MKkNRWt+eZPvmsJ\n" +
+        "qmDPmV0D37L7eF19TIeNkHPN/H7oYdcsHi7p5TY0BNru+pIs1twtx9nv9CaQWqDg\n" +
+        "lEltfgXjaQqREmtZ0pnxSgJgLxZda8NpnedSzTlcd76YEnyow09NthJPWOnNc/If\n" +
+        "kKWOUUZiLaYokNMiYOHCG3ua7b7O/C9snzUaPZclRJNJ/1+7TPEVwKTpGYk/D2dJ\n" +
+        "Wp49WU7C000Gh18o36TjKv6A7PW/w2Yy2YS2SVVK6Wv8nhDEj4TZlqv8L7hePGS+\n" +
+        "y0hL480pAgMBAAECggEBAJyP1zk+IkloIBtu7+wrdCU6HoDHKMjjlzrehHoOTI4Z\n" +
+        "F0vdaMkE6J4vrYCyz0kEPjKW/e/jxvT2wxHm8xEdtuApS61+mWJFmXTcMlNzdJnR\n" +
+        "Mr6s+gW67fAHngA94OgGFeTtyX2PFxdgeM/6vFMqLZD7S+w0SnR7WEpvla4iB7On\n" +
+        "lXqhJKVQeVc+IpByg/S4MmJb91jck73GltCaCL/b6BTrsz+zc/AY5tb8JInxjMZ9\n" +
+        "jmjmA+s6l7tnBrFQfJHlF9a374lxCOtZTxyxVJjD7tQcGpsUpSHXZGdpDcT34qYT\n" +
+        "UGh0yp2Mc/1PfWni5gS/6UGLrYmT57RRCn5YJBJTEkkCgYEA/XPCNehFaOMSxOZh\n" +
+        "OGBVhQ+eRAmdpJfMhSUsDdEdQLZyWGmZsMTHjZZrwevBX/D0dxQYDv/sAl0GZomJ\n" +
+        "d6iRCHlscycwx5Q0U/EpacsgRlYHz1nMRzXqS3Ry+8O8qQlliqCLUM7SfVgzdI5/\n" +
+        "ll9JMrng9NnRl8ccjEdOGK8g/MMCgYEA4eriKMfRslGY4uOQoTPbuEJSMMwQ2X4k\n" +
+        "lPj1p+xSQfU9QBaWJake67oBj3vpCxqN7/VkvCIeC6LCjhLpWHCn4EkdGiqkEdWz\n" +
+        "m5CHzpzVIgznzWnbt0rCVL2KdL+ihgY8KPDdsZ6tZrABHuYhsWkAu10wyvuQYM88\n" +
+        "3u6yOIQn36MCgYEAk5qR1UEzAxWTPbaJkgKQa5Cf9DHBbDS3eCcg098f8SsPxquh\n" +
+        "RRAkwzGCCgqZsJ0sUhkStdGXifzRGHAq7dPuuwe0ABAn2WNXYjeFjcYtQqkhnUFH\n" +
+        "tYURsOXdfQAOZEdDqos691GrxjHSraO7bECL6Y3VE+Oyq3jbCFsSgU+kn28CgYBT\n" +
+        "mrXZO6FJqVK33FlAns1YEgsSjeJKapklHEDkxNroF9Zz6ifkhgKwX6SGMefbORd/\n" +
+        "zsNZsBKIYdI3+52pIf+uS8BeV5tiEkCmeEUZ3AYv1LDP3rX1zc++xmn/rI97o8EN\n" +
+        "sZ2JRtyK3OV9RtL/MYmYzPLqm1Ah02+GXLVNnvKWmwKBgE8Ble8CzrXYuuPdGxXz\n" +
+        "BZU6HnXQrmTUcgeze0tj8SDHzCfsGsaG6pHrVNkT7CKsRuCHTZLM0kXmUijLFKuP\n" +
+        "5xyE257z4IbbEbs+tcbB3p28n4/47MzZkSR3kt8+FrsEMZq5oOHbFTGzgp9dhZCC\n" +
+        "dKUqlw5BPHdbxoWB/JpSHGCV"
+        };
+
+    // Private key names of endEntityPrivateKeys.
+    private final static String[] endEntityPrivateKeyNames = {
+        "EC",
+        "RSA"
+        };
+
+    /*
+     * Run the test case.
+     */
+    public void run() throws Exception {
+        SSLEngine serverEngine = createServerEngine();
+
+        //
+        // Create and size the buffers appropriately.
+        //
+        SSLSession session = serverEngine.getSession();
+        ByteBuffer serverAppInbound =
+            ByteBuffer.allocate(session.getApplicationBufferSize());
+        ByteBuffer clientHello =
+            ByteBuffer.allocate(session.getPacketBufferSize());
+
+        //
+        // Generate a ClientHello message, and check if the server
+        // engine can read it or not.
+        //
+        clientHello.put(createClientHelloMessage());
+        clientHello.flip();
+
+        SSLEngineResult serverResult =
+                serverEngine.unwrap(clientHello, serverAppInbound);
+        log("Server unwrap: ", serverResult);
+        runDelegatedTasks(serverResult, serverEngine);
+
+        //
+        // Generate server responses to the ClientHello request.
+        //
+        ByteBuffer clientNetInbound =
+            ByteBuffer.allocate(session.getPacketBufferSize());
+        ByteBuffer clientAppInbound =
+            ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+
+        serverResult = serverEngine.wrap(clientAppInbound, clientNetInbound);
+        log("Server wrap: ", serverResult);
+        runDelegatedTasks(serverResult, serverEngine);
+    }
+
+    /*
+     * Create a ClientHello message.
+     */
+    abstract protected byte[] createClientHelloMessage();
+
+    /*
+     * Create an instance of SSLContext for client use.
+     */
+    protected SSLContext createClientSSLContext() throws Exception {
+        return createSSLContext(trustedCertStrs, null, null, null);
+    }
+
+    /*
+     * Create an instance of SSLContext for server use.
+     */
+    protected SSLContext createServerSSLContext() throws Exception {
+        return createSSLContext(null,
+                endEntityCertStrs, endEntityPrivateKeys,
+                endEntityPrivateKeyNames);
+    }
+
+    /*
+     * Create an instance of SSLContext with the specified trust/key materials.
+     */
+    protected SSLContext createSSLContext(
+            String[] trustedMaterials,
+            String[] keyMaterialCerts,
+            String[] keyMaterialKeys,
+            String[] keyMaterialKeyAlgs) throws Exception {
+
+        KeyStore ts = null;     // trust store
+        KeyStore ks = null;     // key store
+        char passphrase[] = "passphrase".toCharArray();
+
+        // Generate certificate from cert string.
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // Import the trused certs.
+        ByteArrayInputStream is;
+        if (trustedMaterials != null && trustedMaterials.length != 0) {
+            ts = KeyStore.getInstance("JKS");
+            ts.load(null, null);
+
+            Certificate[] trustedCert =
+                    new Certificate[trustedMaterials.length];
+            for (int i = 0; i < trustedMaterials.length; i++) {
+                String trustedCertStr = trustedMaterials[i];
+
+                is = new ByteArrayInputStream(trustedCertStr.getBytes());
+                try {
+                    trustedCert[i] = cf.generateCertificate(is);
+                } finally {
+                    is.close();
+                }
+
+                ts.setCertificateEntry("trusted-cert-" + i, trustedCert[i]);
+            }
+        }
+
+        // Import the key materials.
+        //
+        // Note that certification pathes bigger than one are not supported yet.
+        boolean hasKeyMaterials =
+            (keyMaterialCerts != null) && (keyMaterialCerts.length != 0) &&
+            (keyMaterialKeys != null) && (keyMaterialKeys.length != 0) &&
+            (keyMaterialKeyAlgs != null) && (keyMaterialKeyAlgs.length != 0) &&
+            (keyMaterialCerts.length == keyMaterialKeys.length) &&
+            (keyMaterialCerts.length == keyMaterialKeyAlgs.length);
+        if (hasKeyMaterials) {
+            ks = KeyStore.getInstance("JKS");
+            ks.load(null, null);
+
+            for (int i = 0; i < keyMaterialCerts.length; i++) {
+                String keyCertStr = keyMaterialCerts[i];
+
+                // generate the private key.
+                PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(keyMaterialKeys[i]));
+                KeyFactory kf =
+                    KeyFactory.getInstance(keyMaterialKeyAlgs[i]);
+                PrivateKey priKey = kf.generatePrivate(priKeySpec);
+
+                // generate certificate chain
+                is = new ByteArrayInputStream(keyCertStr.getBytes());
+                Certificate keyCert = null;
+                try {
+                    keyCert = cf.generateCertificate(is);
+                } finally {
+                    is.close();
+                }
+
+                Certificate[] chain = new Certificate[] { keyCert };
+
+                // import the key entry.
+                ks.setKeyEntry("cert-" + i, priKey, passphrase, chain);
+            }
+        }
+
+        // Create an SSLContext object.
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ts);
+
+        SSLContext context = SSLContext.getInstance("TLS");
+        if (hasKeyMaterials && ks != null) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            context.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return context;
+    }
+
+    /*
+     * Create an instance of SSLEngine in client mode.
+     */
+    protected SSLEngine createClientEngine() throws Exception {
+        return createClientEngine(createClientSSLContext());
+    }
+
+    /*
+     * Create an instance of SSLEngine in client mode with the
+     * specified SSLContext object.
+     */
+    protected SSLEngine createClientEngine(
+        SSLContext context) throws Exception {
+
+        SSLEngine engine = context.createSSLEngine();
+        engine.setUseClientMode(true);
+
+        /*
+         * Customize the SSLEngine object.
+         */
+        // blank
+
+        return engine;
+    }
+
+    /*
+     * Create an instance of SSLEngine in server mode.
+     */
+    protected SSLEngine createServerEngine() throws Exception {
+        return createServerEngine(createServerSSLContext());
+    }
+
+    /*
+     * Create an instance of SSLEngine in server mode with the
+     * specified SSLContext object.
+     */
+    protected SSLEngine createServerEngine(
+        SSLContext context) throws Exception {
+
+        SSLEngine engine = context.createSSLEngine();
+        engine.setUseClientMode(false);
+
+        /*
+         * Customize the SSLEngine object.
+         */
+        engine.setNeedClientAuth(false);
+
+        return engine;
+    }
+
+    /*
+     * Run the delagayed tasks if any.
+     *
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    protected static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    /*
+     * Logging the specificated message and the SSLEngine operation result.
+     */
+    protected static void log(String str, SSLEngineResult result) {
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", consumed: " +
+            result.bytesConsumed() + "/produced: " + result.bytesProduced() +
+            " bytes");
+
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    /*
+     * Logging the specificated message.
+     */
+    protected static void log(String str) {
+        System.out.println(str);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/CacertsExplorer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 Google Inc. 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.
+ *
+ * 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.
+ */
+
+import java.security.KeyStore;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+/*
+ * @test
+ * @bug 8194960
+ * @summary Sanity check trust manager defaults/cacerts.
+ */
+
+/**
+ * Explores the set of root certificates.
+ * Also useful as a standalone program.
+ *
+ * Prior to JEP 319, stock openjdk fails this because no root
+ * certificates were checked into the repo.
+ */
+public class CacertsExplorer {
+    public static void main(String[] args) throws Throwable {
+        String defaultAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
+        if (!defaultAlgorithm.equals("PKIX")) {
+            throw new AssertionError(
+                "Expected default algorithm PKIX, got " + defaultAlgorithm);
+        }
+
+        TrustManagerFactory trustManagerFactory =
+            TrustManagerFactory.getInstance(defaultAlgorithm);
+        trustManagerFactory.init((KeyStore) null);
+        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
+        if (trustManagers.length != 1) {
+            throw new AssertionError(
+                "Expected exactly one TrustManager, got "
+                + Arrays.toString(trustManagers));
+        }
+        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
+
+        X509Certificate[] acceptedIssuers = trustManager.getAcceptedIssuers();
+        if (acceptedIssuers.length == 0) {
+            throw new AssertionError(
+                "no accepted issuers - cacerts file configuration problem?");
+        }
+        Arrays.stream(acceptedIssuers)
+            .map(X509Certificate::getIssuerX500Principal)
+            .forEach(System.out::println);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/ciphersuites/CheckCipherSuites.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2002, 2019, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4750141 4895631 8217579
+ * @summary Check enabled and supported ciphersuites are correct
+ * @run main CheckCipherSuites default
+ * @run main/othervm CheckCipherSuites limited
+ */
+
+import java.util.*;
+import java.security.Security;
+import javax.net.ssl.*;
+
+public class CheckCipherSuites {
+
+    // List of enabled cipher suites when the "crypto.policy" security
+    // property is set to "unlimited" (the default value).
+    private final static String[] ENABLED_DEFAULT = {
+        "TLS_AES_128_GCM_SHA256",
+        "TLS_AES_256_GCM_SHA384",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+        "TLS_RSA_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
+    };
+
+    // List of enabled cipher suites when the "crypto.policy" security
+    // property is set to "limited".
+    private final static String[] ENABLED_LIMITED = {
+        "TLS_AES_128_GCM_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
+    };
+
+    // List of supported cipher suites when the "crypto.policy" security
+    // property is set to "unlimited" (the default value).
+    private final static String[] SUPPORTED_DEFAULT = {
+        "TLS_AES_128_GCM_SHA256",
+        "TLS_AES_256_GCM_SHA384",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+        "TLS_RSA_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
+    };
+
+    // List of supported cipher suites when the "crypto.policy" security
+    // property is set to "limited".
+    private final static String[] SUPPORTED_LIMITED = {
+        "TLS_AES_128_GCM_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV"
+    };
+
+    private static void showSuites(String[] suites) {
+        if ((suites == null) || (suites.length == 0)) {
+            System.out.println("<none>");
+        }
+        for (int i = 0; i < suites.length; i++) {
+            System.out.println("  " + suites[i]);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        long start = System.currentTimeMillis();
+
+        if (args.length != 1) {
+            throw new Exception("One arg required");
+        }
+
+        String[] ENABLED;
+        String[] SUPPORTED;
+        if (args[0].equals("default")) {
+            ENABLED = ENABLED_DEFAULT;
+            SUPPORTED = SUPPORTED_DEFAULT;
+        } else if (args[0].equals("limited")) {
+            Security.setProperty("crypto.policy", "limited");
+            ENABLED = ENABLED_LIMITED;
+            SUPPORTED = SUPPORTED_LIMITED;
+        } else {
+            throw new Exception("Illegal argument");
+        }
+
+        SSLSocketFactory factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
+        SSLSocket socket = (SSLSocket)factory.createSocket();
+        String[] enabled = socket.getEnabledCipherSuites();
+
+        System.out.println("Default enabled ciphersuites:");
+        showSuites(enabled);
+
+        if (Arrays.equals(ENABLED, enabled) == false) {
+            System.out.println("*** MISMATCH, should be ***");
+            showSuites(ENABLED);
+            throw new Exception("Enabled ciphersuite mismatch");
+        }
+        System.out.println("OK");
+        System.out.println();
+
+        String[] supported = socket.getSupportedCipherSuites();
+        System.out.println("Supported ciphersuites:");
+        showSuites(supported);
+
+        if (Arrays.equals(SUPPORTED, supported) == false) {
+            System.out.println("*** MISMATCH, should be ***");
+            showSuites(SUPPORTED);
+            throw new Exception("Supported ciphersuite mismatch");
+        }
+        System.out.println("OK");
+
+        long end = System.currentTimeMillis();
+        System.out.println("Done (" + (end - start) + " ms).");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/ciphersuites/CipherSuitesInOrder.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,264 @@
+/*
+ * 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7174244
+ * @summary NPE in Krb5ProxyImpl.getServerKeys()
+ * @ignore the dependent implementation details are changed
+ * @run main/othervm CipherSuitesInOrder
+ */
+
+import java.util.*;
+import javax.net.ssl.*;
+import java.security.Security;
+
+public class CipherSuitesInOrder {
+
+    // supported ciphersuites
+    private final static List<String> supportedCipherSuites =
+            Arrays.<String>asList(
+        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
+        "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384",
+        "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256",
+
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+        "TLS_RSA_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
+        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+        "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+
+        "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+        "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+        "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+        "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+        "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
+        "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+        "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+
+        "TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
+
+        "TLS_DH_anon_WITH_AES_256_GCM_SHA384",
+        "TLS_DH_anon_WITH_AES_128_GCM_SHA256",
+
+        "TLS_DH_anon_WITH_AES_256_CBC_SHA256",
+        "TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
+        "TLS_DH_anon_WITH_AES_256_CBC_SHA",
+        "TLS_DH_anon_WITH_AES_128_CBC_SHA256",
+        "TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
+        "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+        "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
+        "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+
+        "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
+        "TLS_ECDHE_RSA_WITH_RC4_128_SHA",
+        "SSL_RSA_WITH_RC4_128_SHA",
+        "TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
+        "TLS_ECDH_RSA_WITH_RC4_128_SHA",
+        "SSL_RSA_WITH_RC4_128_MD5",
+        "TLS_ECDH_anon_WITH_RC4_128_SHA",
+        "SSL_DH_anon_WITH_RC4_128_MD5",
+
+        "SSL_RSA_WITH_DES_CBC_SHA",
+        "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+        "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+        "SSL_DH_anon_WITH_DES_CBC_SHA",
+        "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+        "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+        "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+        "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+
+        "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+        "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+
+        "TLS_RSA_WITH_NULL_SHA256",
+        "TLS_ECDHE_ECDSA_WITH_NULL_SHA",
+        "TLS_ECDHE_RSA_WITH_NULL_SHA",
+        "SSL_RSA_WITH_NULL_SHA",
+        "TLS_ECDH_ECDSA_WITH_NULL_SHA",
+        "TLS_ECDH_RSA_WITH_NULL_SHA",
+        "TLS_ECDH_anon_WITH_NULL_SHA",
+        "SSL_RSA_WITH_NULL_MD5",
+
+        "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
+        "TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
+        "TLS_KRB5_WITH_RC4_128_SHA",
+        "TLS_KRB5_WITH_RC4_128_MD5",
+        "TLS_KRB5_WITH_DES_CBC_SHA",
+        "TLS_KRB5_WITH_DES_CBC_MD5",
+        "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
+        "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
+        "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
+        "TLS_KRB5_EXPORT_WITH_RC4_40_MD5"
+    );
+
+    private final static String[] protocols = {
+        "", "SSL", "TLS", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"
+    };
+
+
+    public static void main(String[] args) throws Exception {
+        // show all of the supported cipher suites
+        showSuites(supportedCipherSuites.toArray(new String[0]),
+                                "All supported cipher suites");
+
+        for (String protocol : protocols) {
+            System.out.println("//");
+            System.out.println("// " +
+                        "Testing for SSLContext of " + protocol);
+            System.out.println("//");
+            checkForProtocols(protocol);
+        }
+    }
+
+    public static void checkForProtocols(String protocol) throws Exception {
+        SSLContext context;
+        if (protocol.isEmpty()) {
+            context = SSLContext.getDefault();
+        } else {
+            context = SSLContext.getInstance(protocol);
+            context.init(null, null, null);
+        }
+
+        // check the order of default cipher suites of SSLContext
+        SSLParameters parameters = context.getDefaultSSLParameters();
+        checkSuites(parameters.getCipherSuites(),
+                "Default cipher suites in SSLContext");
+
+        // check the order of supported cipher suites of SSLContext
+        parameters = context.getSupportedSSLParameters();
+        checkSuites(parameters.getCipherSuites(),
+                "Supported cipher suites in SSLContext");
+
+
+        //
+        // Check the cipher suites order of SSLEngine
+        //
+        SSLEngine engine = context.createSSLEngine();
+
+        // check the order of endabled cipher suites
+        String[] ciphers = engine.getEnabledCipherSuites();
+        checkSuites(ciphers,
+                "Enabled cipher suites in SSLEngine");
+
+        // check the order of supported cipher suites
+        ciphers = engine.getSupportedCipherSuites();
+        checkSuites(ciphers,
+                "Supported cipher suites in SSLEngine");
+
+        //
+        // Check the cipher suites order of SSLSocket
+        //
+        SSLSocketFactory factory = context.getSocketFactory();
+        try (SSLSocket socket = (SSLSocket)factory.createSocket()) {
+
+            // check the order of endabled cipher suites
+            ciphers = socket.getEnabledCipherSuites();
+            checkSuites(ciphers,
+                "Enabled cipher suites in SSLSocket");
+
+            // check the order of supported cipher suites
+            ciphers = socket.getSupportedCipherSuites();
+            checkSuites(ciphers,
+                "Supported cipher suites in SSLSocket");
+        }
+
+        //
+        // Check the cipher suites order of SSLServerSocket
+        //
+        SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
+        try (SSLServerSocket serverSocket =
+                (SSLServerSocket)serverFactory.createServerSocket()) {
+            // check the order of endabled cipher suites
+            ciphers = serverSocket.getEnabledCipherSuites();
+            checkSuites(ciphers,
+                "Enabled cipher suites in SSLServerSocket");
+
+            // check the order of supported cipher suites
+            ciphers = serverSocket.getSupportedCipherSuites();
+            checkSuites(ciphers,
+                "Supported cipher suites in SSLServerSocket");
+        }
+    }
+
+    private static void checkSuites(String[] suites, String title) {
+        showSuites(suites, title);
+
+        int loc = -1;
+        int index = 0;
+        for (String suite : suites) {
+            index = supportedCipherSuites.indexOf(suite);
+            if (index <= loc) {
+                throw new RuntimeException(suite + " is not in order");
+            }
+
+            loc = index;
+        }
+    }
+
+    private static void showSuites(String[] suites, String title) {
+        System.out.println(title + "[" + suites.length + "]:");
+        for (String suite : suites) {
+            System.out.println("  " + suite);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/interop/CipherTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import java.security.*;
+import java.security.cert.*;
+
+import javax.net.ssl.*;
+
+/**
+ * Test that all ciphersuites work in all versions and all client
+ * authentication types. The way this is setup the server is stateless and
+ * all checking is done on the client side.
+ *
+ * The test is multithreaded to speed it up, especially on multiprocessor
+ * machines. To simplify debugging, run with -DnumThreads=1.
+ *
+ * @author Andreas Sterbenz
+ */
+public class CipherTest {
+
+    // use any available port for the server socket
+    static int serverPort = 0;
+
+    final int THREADS;
+
+    // assume that if we do not read anything for 20 seconds, something
+    // has gone wrong
+    final static int TIMEOUT = 20 * 1000;
+
+    static KeyStore trustStore, keyStore;
+    static X509ExtendedKeyManager keyManager;
+    static X509TrustManager trustManager;
+    static SecureRandom secureRandom;
+
+    private static PeerFactory peerFactory;
+
+    static abstract class Server implements Runnable {
+
+        final CipherTest cipherTest;
+
+        Server(CipherTest cipherTest) throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        public abstract void run();
+
+        void handleRequest(InputStream in, OutputStream out) throws IOException {
+            boolean newline = false;
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                int ch = in.read();
+                if (ch < 0) {
+                    throw new EOFException();
+                }
+                sb.append((char)ch);
+                if (ch == '\r') {
+                    // empty
+                } else if (ch == '\n') {
+                    if (newline) {
+                        // 2nd newline in a row, end of request
+                        break;
+                    }
+                    newline = true;
+                } else {
+                    newline = false;
+                }
+            }
+            String request = sb.toString();
+            if (request.startsWith("GET / HTTP/1.") == false) {
+                throw new IOException("Invalid request: " + request);
+            }
+            out.write("HTTP/1.0 200 OK\r\n\r\n".getBytes());
+        }
+
+    }
+
+    public static class TestParameters {
+
+        CipherSuite cipherSuite;
+        Protocol protocol;
+        String clientAuth;
+
+        TestParameters(CipherSuite cipherSuite, Protocol protocol,
+                String clientAuth) {
+            this.cipherSuite = cipherSuite;
+            this.protocol = protocol;
+            this.clientAuth = clientAuth;
+        }
+
+        boolean isEnabled() {
+            return cipherSuite.supportedByProtocol(protocol);
+        }
+
+        public String toString() {
+            String s = cipherSuite + " in " + protocol + " mode";
+            if (clientAuth != null) {
+                s += " with " + clientAuth + " client authentication";
+            }
+            return s;
+        }
+    }
+
+    private List<TestParameters> tests;
+    private Iterator<TestParameters> testIterator;
+    private SSLSocketFactory factory;
+    private boolean failed;
+
+    private CipherTest(PeerFactory peerFactory) throws IOException {
+        THREADS = Integer.parseInt(System.getProperty("numThreads", "4"));
+        factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
+        SSLSocket socket = (SSLSocket)factory.createSocket();
+        String[] cipherSuites = socket.getSupportedCipherSuites();
+        String[] protocols = socket.getSupportedProtocols();
+        String[] clientAuths = {null, "RSA", "DSA"};
+        tests = new ArrayList<TestParameters>(
+            cipherSuites.length * protocols.length * clientAuths.length);
+        for (int j = 0; j < protocols.length; j++) {
+            String protocol = protocols[j];
+            if (protocol.equals(Protocol.SSLV2HELLO.name)) {
+                System.out.println("Skipping SSLv2Hello protocol");
+                continue;
+            }
+
+            for (int i = 0; i < cipherSuites.length; i++) {
+                String cipherSuite = cipherSuites[i];
+
+                // skip kerberos cipher suites and TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+                if (cipherSuite.startsWith("TLS_KRB5") || cipherSuite.equals(
+                        CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV.name())) {
+                    System.out.println("Skipping unsupported test for " +
+                                        cipherSuite + " of " + protocol);
+                    continue;
+                }
+
+                if (!peerFactory.isSupported(cipherSuite, protocol)) {
+                    continue;
+                }
+
+                for (int k = 0; k < clientAuths.length; k++) {
+                    String clientAuth = clientAuths[k];
+                    // no client with anonymous cipher suites;
+                    // TLS 1.3 doesn't support DSA
+                    if ((clientAuth != null && cipherSuite.contains("DH_anon"))
+                            || ("DSA".equals(clientAuth) && "TLSv1.3".equals(protocol))) {
+                        continue;
+                    }
+                    tests.add(new TestParameters(
+                            CipherSuite.cipherSuite(cipherSuite),
+                            Protocol.protocol(protocol),
+                            clientAuth));
+                }
+            }
+        }
+        testIterator = tests.iterator();
+    }
+
+    synchronized void setFailed() {
+        failed = true;
+    }
+
+    public void run() throws Exception {
+        Thread[] threads = new Thread[THREADS];
+        for (int i = 0; i < THREADS; i++) {
+            try {
+                threads[i] = new Thread(peerFactory.newClient(this),
+                    "Client " + i);
+            } catch (Exception e) {
+                e.printStackTrace();
+                return;
+            }
+            threads[i].start();
+        }
+        try {
+            for (int i = 0; i < THREADS; i++) {
+                threads[i].join();
+            }
+        } catch (InterruptedException e) {
+            setFailed();
+            e.printStackTrace();
+        }
+        if (failed) {
+            throw new Exception("*** Test '" + peerFactory.getName() +
+                "' failed ***");
+        } else {
+            System.out.println("Test '" + peerFactory.getName() +
+                "' completed successfully");
+        }
+    }
+
+    synchronized TestParameters getTest() {
+        if (failed) {
+            return null;
+        }
+        if (testIterator.hasNext()) {
+            return (TestParameters)testIterator.next();
+        }
+        return null;
+    }
+
+    SSLSocketFactory getFactory() {
+        return factory;
+    }
+
+    static abstract class Client implements Runnable {
+
+        final CipherTest cipherTest;
+
+        Client(CipherTest cipherTest) throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        public final void run() {
+            while (true) {
+                TestParameters params = cipherTest.getTest();
+                if (params == null) {
+                    // no more tests
+                    break;
+                }
+                if (!params.isEnabled()) {
+                    System.out.println("Skipping disabled test " + params);
+                    continue;
+                }
+                try {
+                    runTest(params);
+                    System.out.println("Passed " + params);
+                } catch (Exception e) {
+                    cipherTest.setFailed();
+                    System.out.println("** Failed " + params + "**");
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        abstract void runTest(TestParameters params) throws Exception;
+
+        void sendRequest(InputStream in, OutputStream out) throws IOException {
+            out.write("GET / HTTP/1.0\r\n\r\n".getBytes());
+            out.flush();
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                int ch = in.read();
+                if (ch < 0) {
+                    break;
+                }
+                sb.append((char)ch);
+            }
+            String response = sb.toString();
+            if (response.startsWith("HTTP/1.0 200 ") == false) {
+                throw new IOException("Invalid response: " + response);
+            }
+        }
+
+    }
+
+    // for some reason, ${test.src} has a different value when the
+    // test is called from the script and when it is called directly...
+    static String pathToStores = "../../etc";
+    static String pathToStoresSH = ".";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static char[] passwd = "passphrase".toCharArray();
+
+    static File PATH;
+
+    private static KeyStore readKeyStore(String name) throws Exception {
+        File file = new File(PATH, name);
+        InputStream in = new FileInputStream(file);
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(in, passwd);
+        in.close();
+        return ks;
+    }
+
+    public static void main(PeerFactory peerFactory, String[] args)
+            throws Exception {
+        long time = System.currentTimeMillis();
+        String relPath;
+        if ((args != null) && (args.length > 0) && args[0].equals("sh")) {
+            relPath = pathToStoresSH;
+        } else {
+            relPath = pathToStores;
+        }
+        PATH = new File(System.getProperty("test.src", "."), relPath);
+        CipherTest.peerFactory = peerFactory;
+        System.out.println(
+            "Initializing test '" + peerFactory.getName() + "'...");
+        secureRandom = new SecureRandom();
+        secureRandom.nextInt();
+        trustStore = readKeyStore(trustStoreFile);
+        keyStore = readKeyStore(keyStoreFile);
+        KeyManagerFactory keyFactory =
+            KeyManagerFactory.getInstance(
+                KeyManagerFactory.getDefaultAlgorithm());
+        keyFactory.init(keyStore, passwd);
+        keyManager = (X509ExtendedKeyManager)keyFactory.getKeyManagers()[0];
+        trustManager = new AlwaysTrustManager();
+
+        CipherTest cipherTest = new CipherTest(peerFactory);
+        Thread serverThread = new Thread(peerFactory.newServer(cipherTest),
+            "Server");
+        serverThread.setDaemon(true);
+        serverThread.start();
+        System.out.println("Done");
+        cipherTest.run();
+        time = System.currentTimeMillis() - time;
+        System.out.println("Done. (" + time + " ms)");
+    }
+
+    static abstract class PeerFactory {
+
+        abstract String getName();
+
+        abstract Client newClient(CipherTest cipherTest) throws Exception;
+
+        abstract Server newServer(CipherTest cipherTest) throws Exception;
+
+        boolean isSupported(String cipherSuite, String protocol) {
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")
+                    && (cipherSuite.indexOf("_EXPORT_WITH") != -1)) {
+                    System.out.println("Skipping obsoleted test for " +
+                                        cipherSuite + " of " + protocol);
+                    return false;
+            }
+
+            // ignore obsoleted cipher suite for the specified protocol
+            // TODO
+
+            // ignore unsupported cipher suite for the specified protocol
+            // TODO
+
+            return true;
+        }
+    }
+
+}
+
+// we currently don't do any chain verification. we assume that works ok
+// and we can speed up the test. we could also just add a plain certificate
+// chain comparision with our trusted certificates.
+class AlwaysTrustManager implements X509TrustManager {
+
+    public AlwaysTrustManager() {
+
+    }
+
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        // empty
+    }
+
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        // empty
+    }
+
+    public X509Certificate[] getAcceptedIssuers() {
+        return new X509Certificate[0];
+    }
+}
+
+class MyX509KeyManager extends X509ExtendedKeyManager {
+
+    private final X509ExtendedKeyManager keyManager;
+    private String authType;
+
+    MyX509KeyManager(X509ExtendedKeyManager keyManager) {
+        this.keyManager = keyManager;
+    }
+
+    void setAuthType(String authType) {
+        this.authType = authType;
+    }
+
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.getClientAliases(authType, issuers);
+    }
+
+    public String chooseClientAlias(String[] keyType, Principal[] issuers,
+            Socket socket) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.chooseClientAlias(new String[] {authType},
+            issuers, socket);
+    }
+
+    public String chooseEngineClientAlias(String[] keyType,
+            Principal[] issuers, SSLEngine engine) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.chooseEngineClientAlias(new String[] {authType},
+            issuers, engine);
+    }
+
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+            Socket socket) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    public String chooseEngineServerAlias(String keyType, Principal[] issuers,
+            SSLEngine engine) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    public X509Certificate[] getCertificateChain(String alias) {
+        return keyManager.getCertificateChain(alias);
+    }
+
+    public PrivateKey getPrivateKey(String alias) {
+        return keyManager.getPrivateKey(alias);
+    }
+
+}
+
+class DaemonThreadFactory implements ThreadFactory {
+
+    final static ThreadFactory INSTANCE = new DaemonThreadFactory();
+
+    private final static ThreadFactory DEFAULT = Executors.defaultThreadFactory();
+
+    public Thread newThread(Runnable r) {
+        Thread t = DEFAULT.newThread(r);
+        t.setDaemon(true);
+        return t;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/interop/ClientJSSEServerJSSE.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4496785
+ * @summary Verify that all ciphersuites work in all configurations
+ * @author Andreas Sterbenz
+ * @library ../../TLSCommon
+ * @run main/othervm/timeout=300 ClientJSSEServerJSSE
+ */
+import java.security.Security;
+
+public class ClientJSSEServerJSSE {
+
+    public static void main(String[] args) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        CipherTest.main(new JSSEFactory(), args);
+    }
+
+    private static class JSSEFactory extends CipherTest.PeerFactory {
+
+        String getName() {
+            return "Client JSSE - Server JSSE";
+        }
+
+        CipherTest.Client newClient(CipherTest cipherTest) throws Exception {
+            return new JSSEClient(cipherTest);
+        }
+
+        CipherTest.Server newServer(CipherTest cipherTest) throws Exception {
+            return new JSSEServer(cipherTest);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/interop/JSSEClient.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+
+class JSSEClient extends CipherTest.Client {
+
+    private final SSLContext sslContext;
+    private final MyX509KeyManager keyManager;
+
+    JSSEClient(CipherTest cipherTest) throws Exception {
+        super(cipherTest);
+        this.keyManager = new MyX509KeyManager(CipherTest.keyManager);
+        sslContext = SSLContext.getInstance("TLS");
+    }
+
+    void runTest(CipherTest.TestParameters params) throws Exception {
+        SSLSocket socket = null;
+        try {
+            keyManager.setAuthType(params.clientAuth);
+            sslContext.init(
+                    new KeyManager[] { keyManager },
+                    new TrustManager[] { CipherTest.trustManager },
+                    CipherTest.secureRandom);
+            SSLSocketFactory factory = (SSLSocketFactory)sslContext.getSocketFactory();
+            socket = (SSLSocket)factory.createSocket("127.0.0.1", CipherTest.serverPort);
+            socket.setSoTimeout(CipherTest.TIMEOUT);
+            socket.setEnabledCipherSuites(new String[] { params.cipherSuite.name() });
+            socket.setEnabledProtocols(new String[] { params.protocol.name });
+            InputStream in = socket.getInputStream();
+            OutputStream out = socket.getOutputStream();
+            sendRequest(in, out);
+            socket.close();
+            SSLSession session = socket.getSession();
+            session.invalidate();
+            String cipherSuite = session.getCipherSuite();
+            if (!params.cipherSuite.name().equals(cipherSuite)) {
+                throw new Exception("Negotiated ciphersuite mismatch: "
+                        + cipherSuite + " != " + params.cipherSuite);
+            }
+            String protocol = session.getProtocol();
+            if (!params.protocol.name.equals(protocol)) {
+                throw new Exception("Negotiated protocol mismatch: " + protocol
+                        + " != " + params.protocol);
+            }
+            if (cipherSuite.indexOf("DH_anon") == -1) {
+                session.getPeerCertificates();
+            }
+            Certificate[] certificates = session.getLocalCertificates();
+            if (params.clientAuth == null) {
+                if (certificates != null) {
+                    throw new Exception("Local certificates should be null");
+                }
+            } else {
+                if ((certificates == null) || (certificates.length == 0)) {
+                    throw new Exception("Certificates missing");
+                }
+                String keyAlg = certificates[0].getPublicKey().getAlgorithm();
+                if (params.clientAuth != keyAlg) {
+                    throw new Exception("Certificate type mismatch: " + keyAlg + " != " + params.clientAuth);
+                }
+            }
+        } finally {
+            if (socket != null) {
+                socket.close();
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/sanity/interop/JSSEServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+class JSSEServer extends CipherTest.Server {
+
+    SSLServerSocket serverSocket;
+
+    JSSEServer(CipherTest cipherTest) throws Exception {
+        super(cipherTest);
+        SSLContext serverContext = SSLContext.getInstance("TLS");
+        serverContext.init(
+                new KeyManager[] { CipherTest.keyManager },
+                new TrustManager[] { CipherTest.trustManager },
+                CipherTest.secureRandom);
+
+        SSLServerSocketFactory factory
+                = (SSLServerSocketFactory) serverContext.getServerSocketFactory();
+        serverSocket
+                = (SSLServerSocket) factory.createServerSocket(CipherTest.serverPort);
+        CipherTest.serverPort = serverSocket.getLocalPort();
+        serverSocket.setEnabledCipherSuites(factory.getSupportedCipherSuites());
+        serverSocket.setWantClientAuth(true);
+    }
+
+    public void run() {
+        System.out.println("JSSE Server listening on port " + CipherTest.serverPort);
+        Executor exec = Executors.newFixedThreadPool
+                            (cipherTest.THREADS, DaemonThreadFactory.INSTANCE);
+        try {
+            while (true) {
+                final SSLSocket socket = (SSLSocket)serverSocket.accept();
+                socket.setSoTimeout(CipherTest.TIMEOUT);
+                Runnable r = new Runnable() {
+                    public void run() {
+                        try {
+                            InputStream in = socket.getInputStream();
+                            OutputStream out = socket.getOutputStream();
+                            handleRequest(in, out);
+                            out.flush();
+                            socket.close();
+                            socket.getSession().invalidate();
+                        } catch (IOException e) {
+                            cipherTest.setFailed();
+                            e.printStackTrace();
+                        } finally {
+                            if (socket != null) {
+                                try {
+                                    socket.close();
+                                } catch (IOException e) {
+                                    cipherTest.setFailed();
+                                    System.out.println("Exception closing socket on server side:");
+                                    e.printStackTrace();
+                                }
+                            }
+                        }
+                    }
+                };
+                exec.execute(r);
+            }
+        } catch (IOException e) {
+            cipherTest.setFailed();
+            e.printStackTrace();
+            //
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/templates/SSLContextTemplate.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,518 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+//
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+
+/**
+ * SSLContext template to speed up JSSE tests.
+ */
+public interface SSLContextTemplate {
+    /*
+     * Create an instance of SSLContext for client use.
+     */
+    default SSLContext createClientSSLContext() throws Exception {
+        return createSSLContext(trustedCertStrs,
+                endEntityCertStrs, endEntityPrivateKeys,
+                endEntityPrivateKeyAlgs,
+                endEntityPrivateKeyNames,
+                getClientContextParameters());
+    }
+
+    /*
+     * Create an instance of SSLContext for server use.
+     */
+    default SSLContext createServerSSLContext() throws Exception {
+        return createSSLContext(trustedCertStrs,
+                endEntityCertStrs, endEntityPrivateKeys,
+                endEntityPrivateKeyAlgs,
+                endEntityPrivateKeyNames,
+                getServerContextParameters());
+    }
+
+    /*
+     * The parameters used to configure SSLContext.
+     */
+    static final class ContextParameters {
+        final String contextProtocol;
+        final String tmAlgorithm;
+        final String kmAlgorithm;
+
+        ContextParameters(String contextProtocol,
+                String tmAlgorithm, String kmAlgorithm) {
+
+            this.contextProtocol = contextProtocol;
+            this.tmAlgorithm = tmAlgorithm;
+            this.kmAlgorithm = kmAlgorithm;
+        }
+    }
+
+    /*
+     * Get the client side parameters of SSLContext.
+     */
+    default ContextParameters getClientContextParameters() {
+        return new ContextParameters("TLS", "PKIX", "NewSunX509");
+    }
+
+    /*
+     * Get the server side parameters of SSLContext.
+     */
+    default ContextParameters getServerContextParameters() {
+        return new ContextParameters("TLS", "PKIX", "NewSunX509");
+    }
+
+    /*
+     * =======================================
+     * Certificates and keys used in the test.
+     */
+    // Trusted certificates.
+    final static String[] trustedCertStrs = {
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Subject Key Identifier:
+        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
+        "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" +
+        "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" +
+        "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" +
+        "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" +
+        "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" +
+        "2YEHlSQUAbwwqCDEVB5KxaqP\n" +
+        "-----END CERTIFICATE-----",
+        // -----BEGIN PRIVATE KEY-----
+        // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd
+        // XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd
+        // LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp
+        // -----END PRIVATE KEY-----
+
+        // SHA256withRSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Subject Key Identifier:
+        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" +
+        "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" +
+        "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" +
+        "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" +
+        "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" +
+        "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" +
+        "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" +
+        "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" +
+        "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" +
+        "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" +
+        "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" +
+        "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" +
+        "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" +
+        "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" +
+        "-----END CERTIFICATE-----",
+
+        // -----BEGIN PRIVATE KEY-----
+        // MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD
+        // Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB
+        // emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE
+        // +X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq
+        // 7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B
+        // qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4
+        // GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9
+        // rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF
+        // JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2
+        // kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/
+        // 25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/
+        // +5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO
+        // a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS
+        // zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h
+        // De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ
+        // HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W
+        // 9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2
+        // +MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF
+        // 2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg
+        // iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S
+        // Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx
+        // HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C
+        // kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh
+        // 63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K
+        // z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH
+        // zoXBInYwRG9KE/Bw5elhUw==
+        // -----END PRIVATE KEY-----
+
+
+        // SHA256withDSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:18 2018 GMT
+        //     Not After : May 17 07:18:18 2038 GMT
+        // Subject Key Identifier:
+        //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" +
+        "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" +
+        "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" +
+        "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" +
+        "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" +
+        "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" +
+        "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" +
+        "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" +
+        "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" +
+        "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" +
+        "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" +
+        "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" +
+        "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" +
+        "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" +
+        "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" +
+        "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" +
+        "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" +
+        "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" +
+        "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" +
+        "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" +
+        "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" +
+        "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" +
+        "J+g=\n" +
+        "-----END CERTIFICATE-----"
+        // -----BEGIN PRIVATE KEY-----
+        // MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O
+        // Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt
+        // l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk
+        // p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW
+        // Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f
+        // qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA
+        // tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe
+        // 5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY
+        // sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X
+        // xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0
+        // eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU
+        // tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ
+        // xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4=
+        // -----END PRIVATE KEY-----
+    };
+
+    // End entity certificate.
+    final static String[] endEntityCertStrs = {
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Authority Key Identifier:
+        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" +
+        "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" +
+        "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" +
+        "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" +
+        "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" +
+        "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withRSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Authority Key Identifier:
+        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +
+        "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" +
+        "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" +
+        "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" +
+        "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" +
+        "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" +
+        "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" +
+        "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" +
+        "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" +
+        "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" +
+        "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" +
+        "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" +
+        "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" +
+        "e57NnbT7KM+Grw==\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withRSA, curv prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 21 07:18:16 2028 GMT
+        // Authority Key Identifier:
+        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" +
+        "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" +
+        "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" +
+        "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" +
+        "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" +
+        "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" +
+        "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" +
+        "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" +
+        "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withDSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:20 2018 GMT
+        //     Not After : May 17 07:18:20 2038 GMT
+        // Authority Key Identifier:
+        //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+        "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" +
+        "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" +
+        "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" +
+        "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" +
+        "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" +
+        "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" +
+        "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" +
+        "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" +
+        "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" +
+        "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" +
+        "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" +
+        "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" +
+        "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" +
+        "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" +
+        "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" +
+        "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" +
+        "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" +
+        "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" +
+        "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" +
+        "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" +
+        "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" +
+        "-----END CERTIFICATE-----"
+    };
+
+    // Private key in the format of PKCS#8.
+    final static String[] endEntityPrivateKeys = {
+        //
+        // EC private key related to cert endEntityCertStrs[0].
+        //
+        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" +
+        "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" +
+        "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6",
+
+        //
+        // RSA private key related to cert endEntityCertStrs[1].
+        //
+        "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" +
+        "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" +
+        "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" +
+        "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" +
+        "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" +
+        "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" +
+        "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" +
+        "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" +
+        "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" +
+        "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" +
+        "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" +
+        "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" +
+        "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" +
+        "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" +
+        "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" +
+        "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" +
+        "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" +
+        "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" +
+        "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" +
+        "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" +
+        "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" +
+        "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" +
+        "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" +
+        "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" +
+        "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" +
+        "qAL3go42DYeYhu/WnECMeis=",
+
+        //
+        // EC private key related to cert endEntityCertStrs[2].
+        //
+        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" +
+        "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" +
+        "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT",
+
+        //
+        // DSA private key related to cert endEntityCertStrs[3].
+        //
+        "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" +
+        "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" +
+        "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" +
+        "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" +
+        "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" +
+        "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" +
+        "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" +
+        "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" +
+        "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" +
+        "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" +
+        "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" +
+        "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" +
+        "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw="
+        };
+
+    // Private key algorithm of endEntityPrivateKeys.
+    final static String[] endEntityPrivateKeyAlgs = {
+        "EC",
+        "RSA",
+        "EC",
+        "DSA",
+    };
+
+    // Private key names of endEntityPrivateKeys.
+    static final String[] endEntityPrivateKeyNames = {
+        "ecdsa",
+        "rsa",
+        "ec-rsa",
+        "dsa",
+    };
+
+    /*
+     * Create an instance of SSLContext with the specified trust/key materials.
+     */
+    private SSLContext createSSLContext(
+            String[] trustedMaterials,
+            String[] keyMaterialCerts,
+            String[] keyMaterialKeys,
+            String[] keyMaterialKeyAlgs,
+            String[] keyMaterialKeyNames,
+            ContextParameters params) throws Exception {
+
+        KeyStore ts = null;     // trust store
+        KeyStore ks = null;     // key store
+        char passphrase[] = "passphrase".toCharArray();
+
+        // Generate certificate from cert string.
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // Import the trused certs.
+        ByteArrayInputStream is;
+        if (trustedMaterials != null && trustedMaterials.length != 0) {
+            ts = KeyStore.getInstance("JKS");
+            ts.load(null, null);
+
+            Certificate[] trustedCert =
+                    new Certificate[trustedMaterials.length];
+            for (int i = 0; i < trustedMaterials.length; i++) {
+                String trustedCertStr = trustedMaterials[i];
+
+                is = new ByteArrayInputStream(trustedCertStr.getBytes());
+                try {
+                    trustedCert[i] = cf.generateCertificate(is);
+                } finally {
+                    is.close();
+                }
+
+                ts.setCertificateEntry("trusted-cert-" + i, trustedCert[i]);
+            }
+        }
+
+        // Import the key materials.
+        //
+        // Note that certification pathes bigger than one are not supported yet.
+        boolean hasKeyMaterials =
+            (keyMaterialCerts != null) && (keyMaterialCerts.length != 0) &&
+            (keyMaterialKeys != null) && (keyMaterialKeys.length != 0) &&
+            (keyMaterialKeyAlgs != null) && (keyMaterialKeyAlgs.length != 0) &&
+            (keyMaterialCerts.length == keyMaterialKeys.length) &&
+            (keyMaterialCerts.length == keyMaterialKeyAlgs.length);
+        if (hasKeyMaterials) {
+            ks = KeyStore.getInstance("JKS");
+            ks.load(null, null);
+
+            for (int i = 0; i < keyMaterialCerts.length; i++) {
+                String keyCertStr = keyMaterialCerts[i];
+
+                // generate the private key.
+                PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(keyMaterialKeys[i]));
+                KeyFactory kf =
+                    KeyFactory.getInstance(keyMaterialKeyAlgs[i]);
+                PrivateKey priKey = kf.generatePrivate(priKeySpec);
+
+                // generate certificate chain
+                is = new ByteArrayInputStream(keyCertStr.getBytes());
+                Certificate keyCert = null;
+                try {
+                    keyCert = cf.generateCertificate(is);
+                } finally {
+                    is.close();
+                }
+
+                Certificate[] chain = new Certificate[] { keyCert };
+
+                // import the key entry.
+                ks.setKeyEntry("cert-" + keyMaterialKeyNames[i],
+                        priKey, passphrase, chain);
+            }
+        }
+
+        // Create an SSLContext object.
+        TrustManagerFactory tmf =
+                TrustManagerFactory.getInstance(params.tmAlgorithm);
+        tmf.init(ts);
+
+        SSLContext context = SSLContext.getInstance(params.contextProtocol);
+        if (hasKeyMaterials && ks != null) {
+            KeyManagerFactory kmf =
+                    KeyManagerFactory.getInstance(params.kmAlgorithm);
+            kmf.init(ks, passphrase);
+
+            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            context.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return context;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/templates/SSLEngineTemplate.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 1234567
+ * @summary SSLEngine has not yet caused Solaris kernel to panic
+ * @run main/othervm SSLEngineTemplate
+ */
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class SSLEngineTemplate {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+
+    private final SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final char[] passphrase = "passphrase".toCharArray();
+
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        SSLEngineTemplate test = new SSLEngineTemplate();
+        test.runTest();
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLEngineTemplate() throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        // results from client's last operation
+        SSLEngineResult clientResult;
+
+        // results from server's last operation
+        SSLEngineResult serverResult;
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        Exception clientException = null;
+        Exception serverException = null;
+
+        while (!isEngineClosed(clientEngine)
+                || !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            try {
+                clientResult = clientEngine.wrap(clientOut, cTOs);
+                log("client wrap: ", clientResult);
+            } catch (Exception e) {
+                clientException = e;
+                System.out.println("Client wrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(clientEngine);
+            runDelegatedTasks(clientEngine);
+
+            log("----");
+
+            try {
+                serverResult = serverEngine.wrap(serverOut, sTOc);
+                log("server wrap: ", serverResult);
+            } catch (Exception e) {
+                serverException = e;
+                System.out.println("Server wrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(serverEngine);
+            runDelegatedTasks(serverEngine);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("--------");
+
+            try {
+                clientResult = clientEngine.unwrap(sTOc, clientIn);
+                log("client unwrap: ", clientResult);
+            } catch (Exception e) {
+                clientException = e;
+                System.out.println("Client unwrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(clientEngine);
+            runDelegatedTasks(clientEngine);
+
+            log("----");
+
+            try {
+                serverResult = serverEngine.unwrap(cTOs, serverIn);
+                log("server unwrap: ", serverResult);
+            } catch (Exception e) {
+                serverException = e;
+                System.out.println("Server unwrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(serverEngine);
+            runDelegatedTasks(serverEngine);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                log("\tClosing clientEngine's *OUTBOUND*...");
+                clientEngine.closeOutbound();
+                logEngineStatus(clientEngine);
+
+                dataDone = true;
+                log("\tClosing serverEngine's *OUTBOUND*...");
+                serverEngine.closeOutbound();
+                logEngineStatus(serverEngine);
+            }
+        }
+    }
+
+    private static void logEngineStatus(SSLEngine engine) {
+        log("\tCurrent HS State  " + engine.getHandshakeStatus().toString());
+        log("\tisInboundDone():  " + engine.isInboundDone());
+        log("\tisOutboundDone(): " + engine.isOutboundDone());
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(true);
+
+        // Get/set parameters if needed
+        SSLParameters paramsServer = serverEngine.getSSLParameters();
+        serverEngine.setSSLParameters(paramsServer);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+
+        // Get/set parameters if needed
+        SSLParameters paramsClient = clientEngine.getSSLParameters();
+        clientEngine.setSSLParameters(paramsClient);
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngine engine) throws Exception {
+
+        if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("    running delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            logEngineStatus(engine);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                    "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                    "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+                result.getStatus() + "/" + hsStatus + ", " +
+                result.bytesConsumed() + "/" + result.bytesProduced() +
+                " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2011, 2019, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7105780
+ * @summary Add SSLSocket client/SSLEngine server to templates directory.
+ * @run main/othervm SSLSocketSSLEngineTemplate TLSv1
+ * @run main/othervm SSLSocketSSLEngineTemplate TLSv1.1
+ * @run main/othervm SSLSocketSSLEngineTemplate TLSv1.2
+ * @run main/othervm SSLSocketSSLEngineTemplate TLSv1.3
+ */
+
+/**
+ * A SSLSocket/SSLEngine interop test case.  This is not the way to
+ * code SSLEngine-based servers, but works for what we need to do here,
+ * which is to make sure that SSLEngine/SSLSockets can talk to each other.
+ * SSLEngines can use direct or indirect buffers, and different code
+ * is used to get at the buffer contents internally, so we test that here.
+ *
+ * The test creates one SSLSocket (client) and one SSLEngine (server).
+ * The SSLSocket talks to a raw ServerSocket, and the server code
+ * does the translation between byte [] and ByteBuffers that the SSLEngine
+ * can use.  The "transport" layer consists of a Socket Input/OutputStream
+ * and two byte buffers for the SSLEngines:  think of them
+ * as directly connected pipes.
+ *
+ * Again, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      write()         ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      read()          ...             ServerHello/Certificate
+ *      write()         ...             ClientKeyExchange
+ *      write()         ...             ChangeCipherSpec
+ *      write()         ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      read()          ...             ChangeCipherSpec
+ *      read()          ...             Finished
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.nio.*;
+
+public class SSLSocketSSLEngineTemplate {
+
+    /*
+     * Enables logging of the SSL/TLS operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+    private final SSLContext sslc;
+    private SSLEngine serverEngine;     // server-side SSLEngine
+    private SSLSocket clientSocket;
+
+    private final byte[] serverMsg =
+        "Hi there Client, I'm a Server.".getBytes();
+    private final byte[] clientMsg =
+        "Hello Server, I'm a Client! Pleased to meet you!".getBytes();
+
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    private volatile Exception clientException;
+    private volatile Exception serverException;
+
+    /*
+     * For data transport, this example uses local ByteBuffers.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores/trust material.
+     */
+    private static final String pathToStores = "../etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores
+            + "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores
+            + "/" + trustStoreFile;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        String protocol = args[0];
+
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Run the tests with direct and indirect buffers.
+         */
+        SSLSocketSSLEngineTemplate test =
+            new SSLSocketSSLEngineTemplate(protocol);
+        log("-------------------------------------");
+        log("Testing " + protocol + " for direct buffers ...");
+        test.runTest(true);
+
+        log("---------------------------------------");
+        log("Testing " + protocol + " for indirect buffers ...");
+        test.runTest(false);
+
+        log("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLSocketSSLEngineTemplate(String protocol) throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        try (FileInputStream keyFile = new FileInputStream(keyFilename);
+                FileInputStream trustFile = new FileInputStream(trustFilename)) {
+            ks.load(keyFile, passphrase);
+            ts.load(trustFile, passphrase);
+        }
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance(protocol);
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, with the server engine calling wrap/unwrap
+     * regardless of whether data is available or not.  We do this until
+     * we get the application data.  Then we shutdown and go to the next one.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest(boolean direct) throws Exception {
+        clientSocket = null;
+        boolean serverClose = direct;
+
+        // generates the server-side Socket
+        try (ServerSocket serverSocket = new ServerSocket()) {
+            serverSocket.setReuseAddress(false);
+            serverSocket.bind(null);
+            int port = serverSocket.getLocalPort();
+            log("Port: " + port);
+            Thread thread = createClientThread(port, serverClose);
+
+            createSSLEngine();
+            createBuffers(direct);
+
+            // server-side socket that will read
+            try (Socket socket = serverSocket.accept()) {
+                socket.setSoTimeout(500);
+
+                boolean closed = false;
+                // will try to read one more time in case client message
+                // is fragmented to multiple pieces
+                boolean retry = true;
+
+                InputStream is = socket.getInputStream();
+                OutputStream os = socket.getOutputStream();
+
+                SSLEngineResult serverResult;   // results from last operation
+
+                /*
+                 * Examining the SSLEngineResults could be much more involved,
+                 * and may alter the overall flow of the application.
+                 *
+                 * For example, if we received a BUFFER_OVERFLOW when trying
+                 * to write to the output pipe, we could reallocate a larger
+                 * pipe, but instead we wait for the peer to drain it.
+                 */
+                byte[] inbound = new byte[8192];
+                byte[] outbound = new byte[8192];
+
+                while (!isEngineClosed(serverEngine)) {
+                    int len;
+
+                    // Inbound data
+                    log("================");
+
+                    // Read from the Client side.
+                    try {
+                        len = is.read(inbound);
+                        if (len == -1) {
+                            logSocketStatus(clientSocket);
+                            if (clientSocket.isClosed()
+                                    || clientSocket.isOutputShutdown()) {
+                                log("Client socket was closed or shutdown output");
+                                break;
+                            } else {
+                                throw new Exception("Unexpected EOF");
+                            }
+                        }
+                        cTOs.put(inbound, 0, len);
+                    } catch (SocketTimeoutException ste) {
+                        // swallow. Nothing yet, probably waiting on us.
+                    }
+
+                    cTOs.flip();
+
+                    serverResult = serverEngine.unwrap(cTOs, serverIn);
+                    log("server unwrap: ", serverResult);
+                    runDelegatedTasks(serverResult, serverEngine);
+                    cTOs.compact();
+
+                    // Outbound data
+                    log("----");
+
+                    serverResult = serverEngine.wrap(serverOut, sTOc);
+                    log("server wrap: ", serverResult);
+                    runDelegatedTasks(serverResult, serverEngine);
+
+                    sTOc.flip();
+
+                    if ((len = sTOc.remaining()) != 0) {
+                        sTOc.get(outbound, 0, len);
+                        os.write(outbound, 0, len);
+                        // Give the other side a chance to process
+                    }
+
+                    sTOc.compact();
+
+                    if (!closed && (serverOut.remaining() == 0)) {
+                        closed = true;
+
+                        /*
+                         * We'll alternate initiatating the shutdown.
+                         * When the server initiates, it will take one more
+                         * loop, but tests the orderly shutdown.
+                         */
+                        if (serverClose) {
+                            serverEngine.closeOutbound();
+                        }
+                        serverIn.flip();
+
+                        /*
+                         * A sanity check to ensure we got what was sent.
+                         */
+                        if (serverIn.remaining() !=  clientMsg.length) {
+                            if (retry &&
+                                    serverIn.remaining() < clientMsg.length) {
+                                log("Need to read more from client");
+                                serverIn.compact();
+                                retry = false;
+                                continue;
+                            } else {
+                                throw new Exception(
+                                        "Client: Data length error");
+                            }
+                        }
+
+                        for (int i = 0; i < clientMsg.length; i++) {
+                            if (clientMsg[i] != serverIn.get()) {
+                                throw new Exception(
+                                        "Client: Data content error");
+                            }
+                        }
+                        serverIn.compact();
+                    }
+                }
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                // Wait for the client to join up with us.
+                if (thread != null) {
+                    thread.join();
+                }
+            }
+        } finally {
+            if (serverException != null) {
+                if (clientException != null) {
+                    serverException.initCause(clientException);
+                }
+                throw serverException;
+            }
+            if (clientException != null) {
+                if (serverException != null) {
+                    clientException.initCause(serverException);
+                }
+                throw clientException;
+            }
+        }
+    }
+
+    /*
+     * Create a client thread which does simple SSLSocket operations.
+     * We'll write and read one data packet.
+     */
+    private Thread createClientThread(final int port,
+            final boolean serverClose) throws Exception {
+
+        Thread t = new Thread("ClientThread") {
+
+            @Override
+            public void run() {
+                // client-side socket
+                try (SSLSocket sslSocket = (SSLSocket)sslc.getSocketFactory().
+                            createSocket("localhost", port)) {
+                    clientSocket = sslSocket;
+
+                    OutputStream os = sslSocket.getOutputStream();
+                    InputStream is = sslSocket.getInputStream();
+
+                    // write(byte[]) goes in one shot.
+                    os.write(clientMsg);
+
+                    byte[] inbound = new byte[2048];
+                    int pos = 0;
+
+                    int len;
+                    while ((len = is.read(inbound, pos, 2048 - pos)) != -1) {
+                        pos += len;
+                        // Let the client do the closing.
+                        if ((pos == serverMsg.length) && !serverClose) {
+                            sslSocket.close();
+                            break;
+                        }
+                    }
+
+                    if (pos != serverMsg.length) {
+                        throw new Exception("Client:  Data length error");
+                    }
+
+                    for (int i = 0; i < serverMsg.length; i++) {
+                        if (inbound[i] != serverMsg[i]) {
+                            throw new Exception("Client:  Data content error");
+                        }
+                    }
+                } catch (Exception e) {
+                    clientException = e;
+                }
+            }
+        };
+        t.start();
+        return t;
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngine() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.getNeedClientAuth();
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers(boolean direct) {
+
+        SSLSession session = serverEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        if (direct) {
+            serverIn = ByteBuffer.allocateDirect(appBufferMax + 50);
+            cTOs = ByteBuffer.allocateDirect(netBufferMax);
+            sTOc = ByteBuffer.allocateDirect(netBufferMax);
+        } else {
+            serverIn = ByteBuffer.allocate(appBufferMax + 50);
+            cTOs = ByteBuffer.allocate(netBufferMax);
+            sTOc = ByteBuffer.allocate(netBufferMax);
+        }
+
+        serverOut = ByteBuffer.wrap(serverMsg);
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                        "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void logSocketStatus(Socket socket) {
+        log("##### " + socket + " #####");
+        log("isBound: " + socket.isBound());
+        log("isConnected: " + socket.isConnected());
+        log("isClosed: " + socket.isClosed());
+        log("isInputShutdown: " + socket.isInputShutdown());
+        log("isOutputShutdown: " + socket.isOutputShutdown());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            log("The format of the SSLEngineResult is: \n"
+                    + "\t\"getStatus() / getHandshakeStatus()\" +\n"
+                    + "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str
+                + result.getStatus() + "/" + hsStatus + ", "
+                + result.bytesConsumed() + "/" + result.bytesProduced()
+                + " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            if (debug) {
+                System.err.println(str);
+            } else {
+                System.out.println(str);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/javax/net/ssl/templates/SSLSocketTemplate.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,925 @@
+/*
+ * Copyright (c) 2016, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8161106 8170329
+ * @modules jdk.crypto.ec
+ * @summary Improve SSLSocket test template
+ * @run main/othervm SSLSocketTemplate
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.net.InetSocketAddress;
+import java.net.SocketTimeoutException;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Template to help speed your client/server tests.
+ *
+ * Two examples that use this template:
+ *    test/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java
+ *    test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java
+ */
+public class SSLSocketTemplate {
+
+    /*
+     * ==================
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        (new SSLSocketTemplate()).run();
+    }
+
+    /*
+     * Run the test case.
+     */
+    public void run() throws Exception {
+        bootup();
+    }
+
+    /*
+     * Define the server side application of the test for the specified socket.
+     */
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        // here comes the test logic
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    /*
+     * Define the client side application of the test for the specified socket.
+     * This method is used if the returned value of
+     * isCustomizedClientConnection() is false.
+     *
+     * @param socket may be null is no client socket is generated.
+     *
+     * @see #isCustomizedClientConnection()
+     */
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+    }
+
+    /*
+     * Define the client side application of the test for the specified
+     * server port.  This method is used if the returned value of
+     * isCustomizedClientConnection() is true.
+     *
+     * Note that the client need to connect to the server port by itself
+     * for the actual message exchange.
+     *
+     * @see #isCustomizedClientConnection()
+     */
+    protected void runClientApplication(int serverPort) throws Exception {
+        // blank
+    }
+
+    /*
+     * Create an instance of SSLContext for client use.
+     */
+    protected SSLContext createClientSSLContext() throws Exception {
+        return createSSLContext(trustedCertStrs,
+                endEntityCertStrs, endEntityPrivateKeys,
+                endEntityPrivateKeyAlgs,
+                endEntityPrivateKeyNames,
+                getClientContextParameters());
+    }
+
+    /*
+     * Create an instance of SSLContext for server use.
+     */
+    protected SSLContext createServerSSLContext() throws Exception {
+        return createSSLContext(trustedCertStrs,
+                endEntityCertStrs, endEntityPrivateKeys,
+                endEntityPrivateKeyAlgs,
+                endEntityPrivateKeyNames,
+                getServerContextParameters());
+    }
+
+    /*
+     * The parameters used to configure SSLContext.
+     */
+    protected static final class ContextParameters {
+        final String contextProtocol;
+        final String tmAlgorithm;
+        final String kmAlgorithm;
+
+        ContextParameters(String contextProtocol,
+                String tmAlgorithm, String kmAlgorithm) {
+
+            this.contextProtocol = contextProtocol;
+            this.tmAlgorithm = tmAlgorithm;
+            this.kmAlgorithm = kmAlgorithm;
+        }
+    }
+
+    /*
+     * Get the client side parameters of SSLContext.
+     */
+    protected ContextParameters getClientContextParameters() {
+        return new ContextParameters("TLS", "PKIX", "NewSunX509");
+    }
+
+    /*
+     * Get the server side parameters of SSLContext.
+     */
+    protected ContextParameters getServerContextParameters() {
+        return new ContextParameters("TLS", "PKIX", "NewSunX509");
+    }
+
+    /*
+     * Does the client side use customized connection other than
+     * explicit Socket.connect(), for example, URL.openConnection()?
+     */
+    protected boolean isCustomizedClientConnection() {
+        return false;
+    }
+
+    /*
+     * Configure the server side socket.
+     */
+    protected void configureServerSocket(SSLServerSocket socket) {
+
+    }
+
+    /*
+     * =============================================
+     * Define the client and server side operations.
+     *
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Is the server ready to serve?
+     */
+    private final CountDownLatch serverCondition = new CountDownLatch(1);
+
+    /*
+     * Is the client ready to handshake?
+     */
+    private final CountDownLatch clientCondition = new CountDownLatch(1);
+
+    /*
+     * What's the server port?  Use any free port by default
+     */
+    private volatile int serverPort = 0;
+
+    /*
+     * Define the server side of the test.
+     */
+    private void doServerSide() throws Exception {
+        // kick start the server side service
+        SSLContext context = createServerSSLContext();
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+                (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        configureServerSocket(sslServerSocket);
+        serverPort = sslServerSocket.getLocalPort();
+
+        // Signal the client, the server is ready to accept connection.
+        serverCondition.countDown();
+
+        // Try to accept a connection in 30 seconds.
+        SSLSocket sslSocket;
+        try {
+            sslServerSocket.setSoTimeout(30000);
+            sslSocket = (SSLSocket)sslServerSocket.accept();
+        } catch (SocketTimeoutException ste) {
+            // Ignore the test case if no connection within 30 seconds.
+            System.out.println(
+                "No incoming client connection in 30 seconds. " +
+                "Ignore in server side.");
+            return;
+        } finally {
+            sslServerSocket.close();
+        }
+
+        // handle the connection
+        try {
+            // Is it the expected client connection?
+            //
+            // Naughty test cases or third party routines may try to
+            // connection to this server port unintentionally.  In
+            // order to mitigate the impact of unexpected client
+            // connections and avoid intermittent failure, it should
+            // be checked that the accepted connection is really linked
+            // to the expected client.
+            boolean clientIsReady =
+                    clientCondition.await(30L, TimeUnit.SECONDS);
+
+            if (clientIsReady) {
+                // Run the application in server side.
+                runServerApplication(sslSocket);
+            } else {    // Otherwise, ignore
+                // We don't actually care about plain socket connections
+                // for TLS communication testing generally.  Just ignore
+                // the test if the accepted connection is not linked to
+                // the expected client or the client connection timeout
+                // in 30 seconds.
+                System.out.println(
+                        "The client is not the expected one or timeout. " +
+                        "Ignore in server side.");
+            }
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    private void doClientSide() throws Exception {
+
+        // Wait for server to get started.
+        //
+        // The server side takes care of the issue if the server cannot
+        // get started in 90 seconds.  The client side would just ignore
+        // the test case if the serer is not ready.
+        boolean serverIsReady =
+                serverCondition.await(90L, TimeUnit.SECONDS);
+        if (!serverIsReady) {
+            System.out.println(
+                    "The server is not ready yet in 90 seconds. " +
+                    "Ignore in client side.");
+            return;
+        }
+
+        if (isCustomizedClientConnection()) {
+            // Signal the server, the client is ready to communicate.
+            clientCondition.countDown();
+
+            // Run the application in client side.
+            runClientApplication(serverPort);
+
+            return;
+        }
+
+        SSLContext context = createClientSSLContext();
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
+            try {
+                sslSocket.connect(
+                        new InetSocketAddress("localhost", serverPort), 15000);
+            } catch (IOException ioe) {
+                // The server side may be impacted by naughty test cases or
+                // third party routines, and cannot accept connections.
+                //
+                // Just ignore the test if the connection cannot be
+                // established.
+                System.out.println(
+                        "Cannot make a connection in 15 seconds. " +
+                        "Ignore in client side.");
+                return;
+            }
+
+            // OK, here the client and server get connected.
+
+            // Signal the server, the client is ready to communicate.
+            clientCondition.countDown();
+
+            // There is still a chance in theory that the server thread may
+            // wait client-ready timeout and then quit.  The chance should
+            // be really rare so we don't consider it until it becomes a
+            // real problem.
+
+            // Run the application in client side.
+            runClientApplication(sslSocket);
+        }
+    }
+
+    /*
+     * =============================================
+     * Stuffs to customize the SSLContext instances.
+     */
+
+    /*
+     * =======================================
+     * Certificates and keys used in the test.
+     */
+    // Trusted certificates.
+    private final static String[] trustedCertStrs = {
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Subject Key Identifier:
+        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
+        "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" +
+        "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" +
+        "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" +
+        "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" +
+        "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" +
+        "2YEHlSQUAbwwqCDEVB5KxaqP\n" +
+        "-----END CERTIFICATE-----",
+        // -----BEGIN PRIVATE KEY-----
+        // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd
+        // XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd
+        // LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp
+        // -----END PRIVATE KEY-----
+
+        // SHA256withRSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Subject Key Identifier:
+        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDSTCCAjGgAwIBAgIJAI4ZF3iy8zG+MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpMcY7aWieXDEM1/YJf\n" +
+        "JW27b4nRIFZyEYhEloyGsKTuQiiQjc8cqRZFNXe2vwziDB4IyTEl0Hjl5QF6ZaQE\n" +
+        "huPzzwvQm1pv64KrRXrmj3FisQK8B5OWLty9xp6xDqsaMRoyObLK+oIb20T5fSlE\n" +
+        "evmo1vYjnh8CX0Yzx5Gr5ye6YSEHQvYOWEws8ad17OlyToR2KMeC8w4qo6rs59pW\n" +
+        "g7Mxn9vo22ImDzrtAbTbXbCias3xlE0Bp0h5luyf+5U4UgksoL9B9r2oP4GrLNEV\n" +
+        "oJk57t8lwaR0upiv3CnS8LcJELpegZub5ggqLY8ZPYFQPjlK6IzLOm6rXPgZiZ3m\n" +
+        "RL0CAwEAAaNQME4wHQYDVR0OBBYEFA3dk8n+S701t+iZeJD721o92xVMMB8GA1Ud\n" +
+        "IwQYMBaAFA3dk8n+S701t+iZeJD721o92xVMMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" +
+        "hvcNAQELBQADggEBAJTRC3rKUUhVH07/1+stUungSYgpM08dY4utJq0BDk36BbmO\n" +
+        "0AnLDMbkwFdHEoqF6hQIfpm7SQTmXk0Fss6Eejm8ynYr6+EXiRAsaXOGOBCzF918\n" +
+        "/RuKOzqABfgSU4UBKECLM5bMfQTL60qx+HdbdVIpnikHZOFfmjCDVxoHsGyXc1LW\n" +
+        "Jhkht8IGOgc4PMGvyzTtRFjz01kvrVQZ75aN2E0GQv6dCxaEY0i3ypSzjUWAKqDh\n" +
+        "3e2OLwUSvumcdaxyCdZAOUsN6pDBQ+8VRG7KxnlRlY1SMEk46QgQYLbPDe/+W/yH\n" +
+        "ca4PejicPeh+9xRAwoTpiE2gulfT7Lm+fVM7Ruc=\n" +
+        "-----END CERTIFICATE-----",
+        // -----BEGIN PRIVATE KEY-----
+        // MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6THGO2lonlwxD
+        // Nf2CXyVtu2+J0SBWchGIRJaMhrCk7kIokI3PHKkWRTV3tr8M4gweCMkxJdB45eUB
+        // emWkBIbj888L0Jtab+uCq0V65o9xYrECvAeTli7cvcaesQ6rGjEaMjmyyvqCG9tE
+        // +X0pRHr5qNb2I54fAl9GM8eRq+cnumEhB0L2DlhMLPGndezpck6EdijHgvMOKqOq
+        // 7OfaVoOzMZ/b6NtiJg867QG0212womrN8ZRNAadIeZbsn/uVOFIJLKC/Qfa9qD+B
+        // qyzRFaCZOe7fJcGkdLqYr9wp0vC3CRC6XoGbm+YIKi2PGT2BUD45SuiMyzpuq1z4
+        // GYmd5kS9AgMBAAECggEAFHSoU2MuWwJ+2jJnb5U66t2V1bAcuOE1g5zkWvG/G5z9
+        // rq6Qo5kmB8f5ovdx6tw3MGUOklLwnRXBG3RxDJ1iokz3AvkY1clMNsDPlDsUrQKF
+        // JSO4QUBQTPSZhnsyfR8XHSU+qJ8Y+ohMfzpVv95BEoCzebtXdVgxVegBlcEmVHo2
+        // kMmkRN+bYNsr8eb2r+b0EpyumS39ZgKYh09+cFb78y3T6IFMGcVJTP6nlGBFkmA/
+        // 25pYeCF2tSki08qtMJZQAvKfw0Kviibk7ZxRbJqmc7B1yfnOEHP6ftjuvKl2+RP/
+        // +5P5f8CfIP6gtA0LwSzAqQX/hfIKrGV5j0pCqrD0kQKBgQDeNR6Xi4sXVq79lihO
+        // a1bSeV7r8yoQrS8x951uO+ox+UIZ1MsAULadl7zB/P0er92p198I9M/0Jth3KBuS
+        // zj45mucvpiiGvmQlMKMEfNq4nN7WHOu55kufPswQB2mR4J3xmwI+4fM/nl1zc82h
+        // De8JSazRldJXNhfx0RGFPmgzbwKBgQDWoVXrXLbCAn41oVnWB8vwY9wjt92ztDqJ
+        // HMFA/SUohjePep9UDq6ooHyAf/Lz6oE5NgeVpPfTDkgvrCFVKnaWdwALbYoKXT2W
+        // 9FlyJox6eQzrtHAacj3HJooXWuXlphKSizntfxj3LtMR9BmrmRJOfK+SxNOVJzW2
+        // +MowT20EkwKBgHmpB8jdZBgxI7o//m2BI5Y1UZ1KE5vx1kc7VXzHXSBjYqeV9FeF
+        // 2ZZLP9POWh/1Fh4pzTmwIDODGT2UPhSQy0zq3O0fwkyT7WzXRknsuiwd53u/dejg
+        // iEL2NPAJvulZ2+AuiHo5Z99LK8tMeidV46xoJDDUIMgTG+UQHNGhK5gNAoGAZn/S
+        // Cn7SgMC0CWSvBHnguULXZO9wH1wZAFYNLL44OqwuaIUFBh2k578M9kkke7woTmwx
+        // HxQTjmWpr6qimIuY6q6WBN8hJ2Xz/d1fwhYKzIp20zHuv5KDUlJjbFfqpsuy3u1C
+        // kts5zwI7pr1ObRbDGVyOdKcu7HI3QtR5qqyjwaUCgYABo7Wq6oHva/9V34+G3Goh
+        // 63bYGUnRw2l5BD11yhQv8XzGGZFqZVincD8gltNThB0Dc/BI+qu3ky4YdgdZJZ7K
+        // z51GQGtaHEbrHS5caV79yQ8QGY5mUVH3E+VXSxuIqb6pZq2DH4sTAEFHyncddmOH
+        // zoXBInYwRG9KE/Bw5elhUw==
+        // -----END PRIVATE KEY-----
+
+        // SHA256withDSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:18 2018 GMT
+        //     Not After : May 17 07:18:18 2038 GMT
+        // Subject Key Identifier:
+        //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIErjCCBFSgAwIBAgIJAOktYLNCbr02MAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTgwNTIyMDcxODE4WhcNMzgwNTE3MDcxODE4WjA7MQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Uw\n" +
+        "ggNHMIICOQYHKoZIzjgEATCCAiwCggEBAO5GyPhSm0ze3LSu+gicdULLj05iOfTL\n" +
+        "UvZQ29sYz41zmqrLBQbdKiHqgJu2Re9sgTb5suLNjF047TOLPnU3jhPtWm2X8Xzi\n" +
+        "VGIcHym/Q/MeZxStt/88seqroI3WOKzIML2GcrishT+lcGrtH36Tf1+ue2Snn3PS\n" +
+        "WyxygNqPjllP5uUjYmFLvAf4QLMldkd/D2VxcwsHjB8y5iUZsXezc/LEhRZS/02m\n" +
+        "ivqlRw3AMkq/OVe/ZtxFWsP0nsfxEGdZuaUFpppGfixxFvymrB3+J51cTt+pZBDq\n" +
+        "D2y0DYfc+88iCs4jwHTfcDIpLb538HBjBj2rEgtQESQmB0ooD/+wsPsCIQC1bYch\n" +
+        "gElNtDYL3FgpLgNSUYp7gIWv9ehaC7LO2z7biQKCAQBitvFOnDkUja8NAF7lDpOV\n" +
+        "b5ipQ8SicBLW3kQamxhyuyxgZyy/PojZ/oPorkqW/T/A0rhnG6MssEpAtdiwVB+c\n" +
+        "rBYGo3bcwmExJhdOJ6dYuKFppPWhCwKMHs9npK+lqBMl8l5j58xlcFeC7ZfGf8GY\n" +
+        "GkhFW0c44vEQhMMbac6ZTTP4mw+1t7xJfmDMlLEyIpTXaAAk8uoVLWzQWnR40sHi\n" +
+        "ybvS0u3JxQkb7/y8tOOZu8qlz/YOS7lQ6UxUGX27Ce1E0+agfPphetoRAlS1cezq\n" +
+        "Wa7r64Ga0nkj1kwkcRqjgTiJx0NwnUXr78VAXFhVF95+O3lfqhvdtEGtkhDGPg7N\n" +
+        "A4IBBgACggEBAMmSHQK0w2i+iqUjOPzn0yNEZrzepLlLeQ1tqtn0xnlv5vBAeefD\n" +
+        "Pm9dd3tZOjufVWP7hhEz8xPobb1CS4e3vuQiv5UBfhdPL3f3l9T7JMAKPH6C9Vve\n" +
+        "OQXE5eGqbjsySbcmseHoYUt1WCSnSda1opX8zchX04e7DhGfE2/L9flpYEoSt8lI\n" +
+        "vMNjgOwvKdW3yvPt1/eBBHYNFG5gWPv/Q5KoyCtHS03uqGm4rNc/wZTIEEfd66C+\n" +
+        "QRaUltjOaHmtwOdDHaNqwhYZSVOip+Mo+TfyzHFREcdHLapo7ZXqbdYkRGxRR3d+\n" +
+        "3DfHaraJO0OKoYlPkr3JMvM/MSGR9AnZOcejUDBOMB0GA1UdDgQWBBR2Zp73O91F\n" +
+        "5TvZcjw/8FQ5hjEmUzAfBgNVHSMEGDAWgBR2Zp73O91F5TvZcjw/8FQ5hjEmUzAM\n" +
+        "BgNVHRMEBTADAQH/MAsGCWCGSAFlAwQDAgNHADBEAiBzriYE41M2y9Hy5ppkL0Qn\n" +
+        "dIlNc8JhXT/PHW7GDtViagIgMko8Qoj9gDGPK3+O9E8DC3wGiiF9CObM4LN387ok\n" +
+        "J+g=\n" +
+        "-----END CERTIFICATE-----"
+        // -----BEGIN PRIVATE KEY-----
+        // MIICZQIBADCCAjkGByqGSM44BAEwggIsAoIBAQDuRsj4UptM3ty0rvoInHVCy49O
+        // Yjn0y1L2UNvbGM+Nc5qqywUG3Soh6oCbtkXvbIE2+bLizYxdOO0ziz51N44T7Vpt
+        // l/F84lRiHB8pv0PzHmcUrbf/PLHqq6CN1jisyDC9hnK4rIU/pXBq7R9+k39frntk
+        // p59z0lsscoDaj45ZT+blI2JhS7wH+ECzJXZHfw9lcXMLB4wfMuYlGbF3s3PyxIUW
+        // Uv9Npor6pUcNwDJKvzlXv2bcRVrD9J7H8RBnWbmlBaaaRn4scRb8pqwd/iedXE7f
+        // qWQQ6g9stA2H3PvPIgrOI8B033AyKS2+d/BwYwY9qxILUBEkJgdKKA//sLD7AiEA
+        // tW2HIYBJTbQ2C9xYKS4DUlGKe4CFr/XoWguyzts+24kCggEAYrbxTpw5FI2vDQBe
+        // 5Q6TlW+YqUPEonAS1t5EGpsYcrssYGcsvz6I2f6D6K5Klv0/wNK4ZxujLLBKQLXY
+        // sFQfnKwWBqN23MJhMSYXTienWLihaaT1oQsCjB7PZ6SvpagTJfJeY+fMZXBXgu2X
+        // xn/BmBpIRVtHOOLxEITDG2nOmU0z+JsPtbe8SX5gzJSxMiKU12gAJPLqFS1s0Fp0
+        // eNLB4sm70tLtycUJG+/8vLTjmbvKpc/2Dku5UOlMVBl9uwntRNPmoHz6YXraEQJU
+        // tXHs6lmu6+uBmtJ5I9ZMJHEao4E4icdDcJ1F6+/FQFxYVRfefjt5X6ob3bRBrZIQ
+        // xj4OzQQjAiEAsceWOM8do4etxp2zgnoNXV8PUUyqWhz1+0srcKV7FR4=
+        // -----END PRIVATE KEY-----
+        };
+
+    // End entity certificate.
+    private final static String[] endEntityCertStrs = {
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Authority Key Identifier:
+        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" +
+        "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" +
+        "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" +
+        "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" +
+        "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" +
+        "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withRSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Authority Key Identifier:
+        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDNjCCAh6gAwIBAgIJAO2+yPcFryUTMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOC\n" +
+        "AQ8AMIIBCgKCAQEAszfBobWfZIp8AgC6PiWDDavP65mSvgCXUGxACbxVNAfkLhNR\n" +
+        "QOsHriRB3X1Q3nvO9PetC6wKlvE9jlnDDj7D+1j1r1CHO7ms1fq8rfcQYdkanDtu\n" +
+        "4AlHo8v+SSWX16MIXFRYDj2VVHmyPtgbltcg4zGAuwT746FdLI94uXjJjq1IOr/v\n" +
+        "0VIlwE5ORWH5Xc+5Tj+oFWK0E4a4GHDgtKKhn2m72hN56/GkPKGkguP5NRS1qYYV\n" +
+        "/EFkdyQMOV8J1M7HaicSft4OL6eKjTrgo93+kHk+tv0Dc6cpVBnalX3TorG8QI6B\n" +
+        "cHj1XQd78oAlAC+/jF4pc0mwi0un49kdK9gRfQIDAQABoyMwITAfBgNVHSMEGDAW\n" +
+        "gBQN3ZPJ/ku9NbfomXiQ+9taPdsVTDANBgkqhkiG9w0BAQsFAAOCAQEApXS0nKwm\n" +
+        "Kp8gpmO2yG1rpd1+2wBABiMU4JZaTqmma24DQ3RzyS+V2TeRb29dl5oTUEm98uc0\n" +
+        "GPZvhK8z5RFr4YE17dc04nI/VaNDCw4y1NALXGs+AHkjoPjLyGbWpi1S+gfq2sNB\n" +
+        "Ekkjp6COb/cb9yiFXOGVls7UOIjnVZVd0r7KaPFjZhYh82/f4PA/A1SnIKd1+nfH\n" +
+        "2yk7mSJNC7Z3qIVDL8MM/jBVwiC3uNe5GPB2uwhd7k5LGAVN3j4HQQGB0Sz+VC1h\n" +
+        "92oi6xDa+YBva2fvHuCd8P50DDjxmp9CemC7rnZ5j8egj88w14X44Xjb/Fd/ApG9\n" +
+        "e57NnbT7KM+Grw==\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withRSA, curv prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 21 07:18:16 2028 GMT
+        // Authority Key Identifier:
+        //     0D:DD:93:C9:FE:4B:BD:35:B7:E8:99:78:90:FB:DB:5A:3D:DB:15:4C
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICazCCAVOgAwIBAgIJAO2+yPcFryUUMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n" +
+        "BAYTAlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2Vy\n" +
+        "aXZjZTAeFw0xODA1MjIwNzE4MTZaFw0yODA1MjEwNzE4MTZaMFUxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTEYMBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" +
+        "AQcDQgAE59MERNTlVZ1eeps8Z3Oue5ZkgQdPtD+WIE6tj3PbIKpxGPDxvfNP959A\n" +
+        "yQjEK/ehWQVrCMmNoEkIzY+IIBgB06MjMCEwHwYDVR0jBBgwFoAUDd2Tyf5LvTW3\n" +
+        "6Jl4kPvbWj3bFUwwDQYJKoZIhvcNAQELBQADggEBAFOTVEqs70ykhZiIdrEsF1Ra\n" +
+        "I3B2rLvwXZk52uSltk2/bzVvewA577ZCoxQ1pL7ynkisPfBN1uVYtHjM1VA3RC+4\n" +
+        "+TAK78dnI7otYjWoHp5rvs4l6c/IbOspS290IlNuDUxMErEm5wxIwj+Aukx/1y68\n" +
+        "hOyCvHBLMY2c1LskH1MMBbDuS1aI+lnGpToi+MoYObxGcV458vxuT8+wwV8Fkpvd\n" +
+        "ll8IIFmeNPRv+1E+lXbES6CSNCVaZ/lFhPgdgYKleN7sfspiz50DG4dqafuEAaX5\n" +
+        "xaK1NWXJxTRz0ROH/IUziyuDW6jphrlgit4+3NCzp6vP9hAJQ8Vhcj0n15BKHIQ=\n" +
+        "-----END CERTIFICATE-----",
+
+        // SHA256withDSA, 2048 bits
+        // Validity
+        //     Not Before: May 22 07:18:20 2018 GMT
+        //     Not After : May 17 07:18:20 2038 GMT
+        // Authority Key Identifier:
+        //     76:66:9E:F7:3B:DD:45:E5:3B:D9:72:3C:3F:F0:54:39:86:31:26:53
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIEnDCCBEGgAwIBAgIJAP/jh1qVhNVjMAsGCWCGSAFlAwQDAjA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2UwHhcNMTgwNTIyMDcxODIwWhcNMzgwNTE3MDcxODIwWjBVMQswCQYDVQQGEwJV\n" +
+        "UzENMAsGA1UECgwESmF2YTEdMBsGA1UECwwUU3VuSlNTRSBUZXN0IFNlcml2Y2Ux\n" +
+        "GDAWBgNVBAMMD1JlZ3Jlc3Npb24gVGVzdDCCA0cwggI6BgcqhkjOOAQBMIICLQKC\n" +
+        "AQEAmlavgoJrMcjqWRVcDE2dmWAPREgnzQvneEDef68cprDzjSwvOs5QeFyx75ib\n" +
+        "ado1e6jO/rW1prCGWHDD1oA/Tn4Pk3vu0nUxzvl1qATc+aJbpUU5Op0bvp6LbCsQ\n" +
+        "QslV9FeRh7Eb7bP6gpc/kHCBzEgC1VCK7prccXWy+t6SMOHbND3h+UbckfSaUuaV\n" +
+        "sVJNTD1D6GElfRj4Nmz1BGPfSYvKorwNZEU3gXwFgtDoAcGx7tcyClLpDHfqRfw/\n" +
+        "7yiqLyeiP7D4hl5lMNouJWDlAdMFp0FMgS3s9VDFinIcr6VtBWMTG7+4+czHAB+3\n" +
+        "fvrwlqNzhBn3uFHrekN/w8fNxwIhAJo7Sae1za7IMW0Q6hE5B4b+s2B/FaKPoA4E\n" +
+        "jtZu13B9AoIBAQCOZqLMKfvqZWUgT0PQ3QjR7dAFdd06I9Y3+TOQzZk1+j+vw/6E\n" +
+        "X4vFItX4gihb/u5Q9CdmpwhVGi7bvo+7+/IKeTgoQ6f5+PSug7SrWWUQ5sPwaZui\n" +
+        "zXZJ5nTeZDucFc2yFx0wgnjbPwiUxZklOT7xGiOMtzOTa2koCz5KuIBL+/wPKKxm\n" +
+        "ypo9VoY9xfbdU6LMXZv/lpD5XTM9rYHr/vUTNkukvV6Hpm0YMEWhVZKUJiqCqTqG\n" +
+        "XHaleOxSw6uQWB/+TznifcC7gB48UOQjCqOKf5VuwQneJLhlhU/jhRV3xtr+hLZa\n" +
+        "hW1wYhVi8cjLDrZFKlgEQqhB4crnJU0mJY+tA4IBBQACggEAID0ezl00/X8mv7eb\n" +
+        "bzovum1+DEEP7FM57k6HZEG2N3ve4CW+0m9Cd+cWPz8wkZ+M0j/Eqa6F0IdbkXEc\n" +
+        "Q7CuzvUyJ57xQ3L/WCgXsiS+Bh8O4Mz7GwW22CGmHqafbVv+hKBfr8MkskO6GJUt\n" +
+        "SUF/CVLzB4gMIvZMH26tBP2xK+i7FeEK9kT+nGdzQSZBAhFYpEVCBplHZO24/OYq\n" +
+        "1DNoU327nUuXIhmsfA8N0PjiWbIZIjTPwBGr9H0LpATI7DIDNcvRRvtROP+pBU9y\n" +
+        "fuykPkptg9C0rCM9t06bukpOSaEz/2VIQdLE8fHYFA6pHZ6CIc2+5cfvMgTPhcjz\n" +
+        "W2jCt6MjMCEwHwYDVR0jBBgwFoAUdmae9zvdReU72XI8P/BUOYYxJlMwCwYJYIZI\n" +
+        "AWUDBAMCA0gAMEUCIQCeI5fN08b9BpOaHdc3zQNGjp24FOL/RxlBLeBAorswJgIg\n" +
+        "JEZ8DhYxQy1O7mmZ2UIT7op6epWMB4dENjs0qWPmcKo=\n" +
+        "-----END CERTIFICATE-----"
+        };
+
+    // Private key in the format of PKCS#8.
+    private final static String[] endEntityPrivateKeys = {
+        //
+        // EC private key related to cert endEntityCertStrs[0].
+        //
+        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" +
+        "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" +
+        "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6",
+
+        //
+        // RSA private key related to cert endEntityCertStrs[1].
+        //
+        "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzN8GhtZ9kinwC\n" +
+        "ALo+JYMNq8/rmZK+AJdQbEAJvFU0B+QuE1FA6weuJEHdfVDee870960LrAqW8T2O\n" +
+        "WcMOPsP7WPWvUIc7uazV+ryt9xBh2RqcO27gCUejy/5JJZfXowhcVFgOPZVUebI+\n" +
+        "2BuW1yDjMYC7BPvjoV0sj3i5eMmOrUg6v+/RUiXATk5FYfldz7lOP6gVYrQThrgY\n" +
+        "cOC0oqGfabvaE3nr8aQ8oaSC4/k1FLWphhX8QWR3JAw5XwnUzsdqJxJ+3g4vp4qN\n" +
+        "OuCj3f6QeT62/QNzpylUGdqVfdOisbxAjoFwePVdB3vygCUAL7+MXilzSbCLS6fj\n" +
+        "2R0r2BF9AgMBAAECggEASIkPkMCuw4WdTT44IwERus3IOIYOs2IP3BgEDyyvm4B6\n" +
+        "JP/iihDWKfA4zEl1Gqcni1RXMHswSglXra682J4kui02Ov+vzEeJIY37Ibn2YnP5\n" +
+        "ZjRT2s9GtI/S2o4hl8A/mQb2IMViFC+xKehTukhV4j5d6NPKk0XzLR7gcMjnYxwn\n" +
+        "l21fS6D2oM1xRG/di7sL+uLF8EXLRzfiWDNi12uQv4nwtxPKvuKhH6yzHt7YqMH0\n" +
+        "46pmDKDaxV4w1JdycjCb6NrCJOYZygoQobuZqOQ30UZoZsPJrtovkncFr1e+lNcO\n" +
+        "+aWDfOLCtTH046dEQh5oCShyXMybNlry/QHsOtHOwQKBgQDh2iIjs+FPpQy7Z3EX\n" +
+        "DGEvHYqPjrYO9an2KSRr1m9gzRlWYxKY46WmPKwjMerYtra0GP+TBHrgxsfO8tD2\n" +
+        "wUAII6sd1qup0a/Sutgf2JxVilLykd0+Ge4/Cs51tCdJ8EqDV2B6WhTewOY2EGvg\n" +
+        "JiKYkeNwgRX/9M9CFSAMAk0hUQKBgQDLJAartL3DoGUPjYtpJnfgGM23yAGl6G5r\n" +
+        "NSXDn80BiYIC1p0bG3N0xm3yAjqOtJAUj9jZbvDNbCe3GJfLARMr23legX4tRrgZ\n" +
+        "nEdKnAFKAKL01oM+A5/lHdkwaZI9yyv+hgSVdYzUjB8rDmzeVQzo1BT7vXypt2yV\n" +
+        "6O1OnUpCbQKBgA/0rzDChopv6KRcvHqaX0tK1P0rYeVQqb9ATNhpf9jg5Idb3HZ8\n" +
+        "rrk91BNwdVz2G5ZBpdynFl9G69rNAMJOCM4KZw5mmh4XOEq09Ivba8AHU7DbaTv3\n" +
+        "7QL7KnbaUWRB26HHzIMYVh0el6T+KADf8NXCiMTr+bfpfbL3dxoiF3zhAoGAbCJD\n" +
+        "Qse1dBs/cKYCHfkSOsI5T6kx52Tw0jS6Y4X/FOBjyqr/elyEexbdk8PH9Ar931Qr\n" +
+        "NKMvn8oA4iA/PRrXX7M2yi3YQrWwbkGYWYjtzrzEAdzmg+5eARKAeJrZ8/bg9l3U\n" +
+        "ttKaItJsDPlizn8rngy3FsJpR9aSAMK6/+wOiYkCgYEA1tZkI1rD1W9NYZtbI9BE\n" +
+        "qlJVFi2PBOJMKNuWdouPX3HLQ72GJSQff2BFzLTELjweVVJ0SvY4IipzpQOHQOBy\n" +
+        "5qh/p6izXJZh3IHtvwVBjHoEVplg1b2+I5e3jDCfqnwcQw82dW5SxOJMg1h/BD0I\n" +
+        "qAL3go42DYeYhu/WnECMeis=",
+
+        //
+        // EC private key related to cert endEntityCertStrs[2].
+        //
+        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGVc7hICpmp91jbYe\n" +
+        "nrr8nYHD37RZP3VENY+szuA7WjuhRANCAATn0wRE1OVVnV56mzxnc657lmSBB0+0\n" +
+        "P5YgTq2Pc9sgqnEY8PG980/3n0DJCMQr96FZBWsIyY2gSQjNj4ggGAHT",
+
+        //
+        // DSA private key related to cert endEntityCertStrs[3].
+        //
+        "MIICZQIBADCCAjoGByqGSM44BAEwggItAoIBAQCaVq+CgmsxyOpZFVwMTZ2ZYA9E\n" +
+        "SCfNC+d4QN5/rxymsPONLC86zlB4XLHvmJtp2jV7qM7+tbWmsIZYcMPWgD9Ofg+T\n" +
+        "e+7SdTHO+XWoBNz5olulRTk6nRu+notsKxBCyVX0V5GHsRvts/qClz+QcIHMSALV\n" +
+        "UIrumtxxdbL63pIw4ds0PeH5RtyR9JpS5pWxUk1MPUPoYSV9GPg2bPUEY99Ji8qi\n" +
+        "vA1kRTeBfAWC0OgBwbHu1zIKUukMd+pF/D/vKKovJ6I/sPiGXmUw2i4lYOUB0wWn\n" +
+        "QUyBLez1UMWKchyvpW0FYxMbv7j5zMcAH7d++vCWo3OEGfe4Uet6Q3/Dx83HAiEA\n" +
+        "mjtJp7XNrsgxbRDqETkHhv6zYH8Voo+gDgSO1m7XcH0CggEBAI5moswp++plZSBP\n" +
+        "Q9DdCNHt0AV13Toj1jf5M5DNmTX6P6/D/oRfi8Ui1fiCKFv+7lD0J2anCFUaLtu+\n" +
+        "j7v78gp5OChDp/n49K6DtKtZZRDmw/Bpm6LNdknmdN5kO5wVzbIXHTCCeNs/CJTF\n" +
+        "mSU5PvEaI4y3M5NraSgLPkq4gEv7/A8orGbKmj1Whj3F9t1Tosxdm/+WkPldMz2t\n" +
+        "gev+9RM2S6S9XoembRgwRaFVkpQmKoKpOoZcdqV47FLDq5BYH/5POeJ9wLuAHjxQ\n" +
+        "5CMKo4p/lW7BCd4kuGWFT+OFFXfG2v6EtlqFbXBiFWLxyMsOtkUqWARCqEHhyucl\n" +
+        "TSYlj60EIgIgLfA75+8KcKxdN8mr6gzGjQe7jPFGG42Ejhd7Q2F4wuw="
+        };
+
+    // Private key algorithm of endEntityPrivateKeys.
+    private final static String[] endEntityPrivateKeyAlgs = {
+        "EC",
+        "RSA",
+        "EC",
+        "DSA",
+        };
+
+    // Private key names of endEntityPrivateKeys.
+    private final static String[] endEntityPrivateKeyNames = {
+        "ecdsa",
+        "rsa",
+        "ec-rsa",
+        "dsa",
+        };
+
+    /*
+     * Create an instance of SSLContext with the specified trust/key materials.
+     */
+    private SSLContext createSSLContext(
+            String[] trustedMaterials,
+            String[] keyMaterialCerts,
+            String[] keyMaterialKeys,
+            String[] keyMaterialKeyAlgs,
+            String[] keyMaterialKeyNames,
+            ContextParameters params) throws Exception {
+
+        KeyStore ts = null;     // trust store
+        KeyStore ks = null;     // key store
+        char passphrase[] = "passphrase".toCharArray();
+
+        // Generate certificate from cert string.
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // Import the trused certs.
+        ByteArrayInputStream is;
+        if (trustedMaterials != null && trustedMaterials.length != 0) {
+            ts = KeyStore.getInstance("JKS");
+            ts.load(null, null);
+
+            Certificate[] trustedCert =
+                    new Certificate[trustedMaterials.length];
+            for (int i = 0; i < trustedMaterials.length; i++) {
+                String trustedCertStr = trustedMaterials[i];
+
+                is = new ByteArrayInputStream(trustedCertStr.getBytes());
+                try {
+                    trustedCert[i] = cf.generateCertificate(is);
+                } finally {
+                    is.close();
+                }
+
+                ts.setCertificateEntry("trusted-cert-" + i, trustedCert[i]);
+            }
+        }
+
+        // Import the key materials.
+        //
+        // Note that certification pathes bigger than one are not supported yet.
+        boolean hasKeyMaterials =
+            (keyMaterialCerts != null) && (keyMaterialCerts.length != 0) &&
+            (keyMaterialKeys != null) && (keyMaterialKeys.length != 0) &&
+            (keyMaterialKeyAlgs != null) && (keyMaterialKeyAlgs.length != 0) &&
+            (keyMaterialCerts.length == keyMaterialKeys.length) &&
+            (keyMaterialCerts.length == keyMaterialKeyAlgs.length);
+        if (hasKeyMaterials) {
+            ks = KeyStore.getInstance("JKS");
+            ks.load(null, null);
+
+            for (int i = 0; i < keyMaterialCerts.length; i++) {
+                String keyCertStr = keyMaterialCerts[i];
+
+                // generate the private key.
+                PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(keyMaterialKeys[i]));
+                KeyFactory kf =
+                    KeyFactory.getInstance(keyMaterialKeyAlgs[i]);
+                PrivateKey priKey = kf.generatePrivate(priKeySpec);
+
+                // generate certificate chain
+                is = new ByteArrayInputStream(keyCertStr.getBytes());
+                Certificate keyCert = null;
+                try {
+                    keyCert = cf.generateCertificate(is);
+                } finally {
+                    is.close();
+                }
+
+                Certificate[] chain = new Certificate[] { keyCert };
+
+                // import the key entry.
+                ks.setKeyEntry("cert-" + keyMaterialKeyNames[i],
+                        priKey, passphrase, chain);
+            }
+        }
+
+        // Create an SSLContext object.
+        TrustManagerFactory tmf =
+                TrustManagerFactory.getInstance(params.tmAlgorithm);
+        tmf.init(ts);
+
+        SSLContext context = SSLContext.getInstance(params.contextProtocol);
+        if (hasKeyMaterials && ks != null) {
+            KeyManagerFactory kmf =
+                    KeyManagerFactory.getInstance(params.kmAlgorithm);
+            kmf.init(ks, passphrase);
+
+            context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } else {
+            context.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return context;
+    }
+
+    /*
+     * =================================================
+     * Stuffs to boot up the client-server mode testing.
+     */
+    private Thread clientThread = null;
+    private Thread serverThread = null;
+    private volatile Exception serverException = null;
+    private volatile Exception clientException = null;
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    private static final boolean separateServerThread = false;
+
+    /*
+     * Boot up the testing, used to drive remainder of the test.
+     */
+    private void bootup() throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    private void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        logException("Server died", e);
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                logException("Server failed", e);
+                serverException = e;
+            }
+        }
+    }
+
+    private void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        logException("Client died", e);
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                logException("Client failed", e);
+                clientException = e;
+            }
+        }
+    }
+
+    private synchronized void logException(String prefix, Throwable cause) {
+        System.out.println(prefix + ": " + cause);
+        cause.printStackTrace(System.out);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/HttpsClient/ProxyAuthTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2001, 2017, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4323990 4413069 8160838
+ * @summary HttpsURLConnection doesn't send Proxy-Authorization on CONNECT
+ *     Incorrect checking of proxy server response
+ * @modules jdk.crypto.ec
+ *          java.base/sun.net.www
+ * @library /javax/net/ssl/templates
+ * @run main/othervm ProxyAuthTest fail
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic
+ *      ProxyAuthTest fail
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic,
+ *      ProxyAuthTest fail
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=BAsIc
+ *      ProxyAuthTest fail
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic,Digest
+ *      ProxyAuthTest fail
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Unknown,bAsIc
+ *      ProxyAuthTest fail
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=
+ *      ProxyAuthTest succeed
+ * @run main/othervm
+ *      -Djdk.http.auth.tunneling.disabledSchemes=Digest,NTLM,Negotiate
+ *      ProxyAuthTest succeed
+ * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=UNKNOWN,notKnown
+ *      ProxyAuthTest succeed
+ */
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.Authenticator;
+import java.net.InetSocketAddress;
+import java.net.PasswordAuthentication;
+import java.net.Proxy;
+import java.net.URL;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLContext;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+
+/*
+ * ProxyAuthTest.java -- includes a simple server that can serve
+ * Http get request in both clear and secure channel, and a client
+ * that makes https requests behind the firewall through an
+ * authentication proxy
+ */
+
+public class ProxyAuthTest extends SSLSocketTemplate {
+    private static boolean expectSuccess;
+
+    /*
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        // Get the customized arguments.
+        parseArguments(args);
+
+        (new ProxyAuthTest()).run();
+    }
+
+    @Override
+    protected boolean isCustomizedClientConnection() {
+        return true;
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        String response = "Proxy authentication for tunneling succeeded ..";
+        DataOutputStream out = new DataOutputStream(socket.getOutputStream());
+        try {
+            BufferedReader in = new BufferedReader(
+                    new InputStreamReader(socket.getInputStream()));
+
+            // read the request
+            readRequest(in);
+
+            // retrieve bytecodes
+            byte[] bytecodes = response.getBytes(US_ASCII);
+
+            // send bytecodes in response (assumes HTTP/1.0 or later)
+            out.writeBytes("HTTP/1.0 200 OK\r\n");
+            out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
+            out.writeBytes("Content-Type: text/html\r\n\r\n");
+            out.write(bytecodes);
+            out.flush();
+        } catch (IOException e) {
+            // write out error response
+            out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
+            out.writeBytes("Content-Type: text/html\r\n\r\n");
+            out.flush();
+        }
+    }
+
+    @Override
+    protected void runClientApplication(int serverPort) throws Exception {
+        /*
+         * Set the default SSLSocketFactory.
+         */
+        SSLContext context = createClientSSLContext();
+        HttpsURLConnection.setDefaultSSLSocketFactory(
+                context.getSocketFactory());
+
+        /*
+         * setup up a proxy with authentication information
+         */
+        ProxyTunnelServer ps = setupProxy();
+
+        /*
+         * we want to avoid URLspoofCheck failures in cases where the cert
+         * DN name does not match the hostname in the URL.
+         */
+        HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
+
+        InetSocketAddress paddr =
+                new InetSocketAddress("localhost", ps.getPort());
+        Proxy proxy = new Proxy(Proxy.Type.HTTP, paddr);
+
+        URL url = new URL(
+                "https://" + "localhost:" + serverPort + "/index.html");
+        BufferedReader in = null;
+        HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(proxy);
+        try {
+            in = new BufferedReader(new InputStreamReader(uc.getInputStream()));
+            String inputLine;
+            System.out.print("Client recieved from the server: ");
+            while ((inputLine = in.readLine()) != null) {
+                System.out.println(inputLine);
+            }
+            if (!expectSuccess) {
+                throw new RuntimeException(
+                    "Expected exception/failure to connect, but succeeded.");
+            }
+        } catch (IOException e) {
+            if (expectSuccess) {
+                System.out.println("Client side failed: " + e.getMessage());
+                throw e;
+            }
+
+            // Assert that the error stream is not accessible from the failed
+            // tunnel setup.
+            if (uc.getErrorStream() != null) {
+                throw new RuntimeException("Unexpected error stream.");
+            }
+
+            if (!e.getMessage().contains("Unable to tunnel through proxy") ||
+                !e.getMessage().contains("407")) {
+
+                throw new RuntimeException(
+                        "Expected exception about cannot tunnel, " +
+                        "407, etc, but got", e);
+            } else {
+                // Informative
+                System.out.println(
+                        "Caught expected exception: " + e.getMessage());
+            }
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+
+    private static void parseArguments(String[] args) {
+        if (args[0].equals("succeed")) {
+            expectSuccess = true;
+        } else {
+            expectSuccess = false;
+        }
+    }
+
+    /**
+     * read the response, don't care for the syntax of the request-line
+     * for this testing
+     */
+    private static void readRequest(BufferedReader in) throws IOException {
+        String line = null;
+        System.out.println("Server received: ");
+        do {
+            if (line != null) {
+                System.out.println(line);
+            }
+            line = in.readLine();
+        } while ((line.length() != 0) &&
+                (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
+    }
+
+    private static class NameVerifier implements HostnameVerifier {
+
+        @Override
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    }
+
+    private static ProxyTunnelServer setupProxy() throws IOException {
+        ProxyTunnelServer pserver = new ProxyTunnelServer();
+
+        /*
+         * register a system wide authenticator and setup the proxy for
+         * authentication
+         */
+        Authenticator.setDefault(new TestAuthenticator());
+
+        // register with the username and password
+        pserver.needUserAuth(true);
+        pserver.setUserAuth("Test", "test123");
+
+        pserver.start();
+        return pserver;
+    }
+
+    private static class TestAuthenticator extends Authenticator {
+
+        @Override
+        public PasswordAuthentication getPasswordAuthentication() {
+            return new PasswordAuthentication("Test", "test123".toCharArray());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/HttpsClient/ServerIdentityTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2001, 2016, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4328195
+ * @summary Need to include the alternate subject DN for certs,
+ *          https should check for this
+ * @library /javax/net/ssl/templates
+ * @run main/othervm ServerIdentityTest dnsstore localhost
+ * @run main/othervm ServerIdentityTest ipstore 127.0.0.1
+ *
+ * @author Yingxian Wang
+ */
+
+import java.io.InputStream;
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+
+public final class ServerIdentityTest extends SSLSocketTemplate {
+
+    private static String keystore;
+    private static String hostname;
+    private static SSLContext context;
+
+    /*
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        // Get the customized arguments.
+        initialize(args);
+
+        (new ServerIdentityTest()).run();
+    }
+
+    @Override
+    protected boolean isCustomizedClientConnection() {
+        return true;
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        sslIS.read();
+        BufferedWriter bw = new BufferedWriter(
+                new OutputStreamWriter(socket.getOutputStream()));
+        bw.write("HTTP/1.1 200 OK\r\n\r\n\r\n");
+        bw.flush();
+        socket.getSession().invalidate();
+    }
+
+    @Override
+    protected void runClientApplication(int serverPort) throws Exception {
+        URL url = new URL(
+                "https://" + hostname + ":" + serverPort + "/index.html");
+
+        HttpURLConnection urlc = null;
+        InputStream is = null;
+        try {
+            urlc = (HttpURLConnection)url.openConnection();
+            is = urlc.getInputStream();
+        } finally {
+            if (is != null) {
+                is.close();
+            }
+            if (urlc != null) {
+                urlc.disconnect();
+            }
+        }
+    }
+
+    @Override
+    protected SSLContext createServerSSLContext() throws Exception {
+        return context;
+    }
+
+    @Override
+    protected SSLContext createClientSSLContext() throws Exception {
+        return context;
+    }
+
+    private static void initialize(String[] args) throws Exception {
+        keystore = args[0];
+        hostname = args[1];
+
+        String password = "changeit";
+        String keyFilename =
+                System.getProperty("test.src", ".") + "/" + keystore;
+        String trustFilename =
+                System.getProperty("test.src", ".") + "/" + keystore;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", password);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", password);
+
+        context = SSLContext.getDefault();
+        HttpsURLConnection.setDefaultSSLSocketFactory(
+                context.getSocketFactory());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/HttpsURLConnection/B6216082.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2005, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 6216082
+ * @summary  Redirect problem with HttpsURLConnection using a proxy
+ * @modules java.base/sun.net.www
+ * @library .. /test/lib
+ * @build jdk.test.lib.NetworkConfiguration
+ *        jdk.test.lib.Platform
+ *        HttpCallback TestHttpsServer ClosedChannelList
+ *        HttpTransaction TunnelProxy
+ * @key intermittent
+ * @run main/othervm B6216082
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.util.*;
+
+import jdk.test.lib.NetworkConfiguration;
+
+public class B6216082 {
+    static SimpleHttpTransaction httpTrans;
+    static TestHttpsServer server;
+    static TunnelProxy proxy;
+
+    // it seems there's no proxy ever if a url points to 'localhost',
+    // even if proxy related properties are set. so we need to bind
+    // our simple http proxy and http server to a non-loopback address
+    static InetAddress firstNonLoAddress = null;
+
+    public static void main(String[] args) throws Exception {
+        HostnameVerifier reservedHV =
+            HttpsURLConnection.getDefaultHostnameVerifier();
+        try {
+            // XXX workaround for CNFE
+            Class.forName("java.nio.channels.ClosedByInterruptException");
+            if (!setupEnv()) {
+                return;
+            }
+
+            startHttpServer();
+
+            // https.proxyPort can only be set after the TunnelProxy has been
+            // created as it will use an ephemeral port.
+            System.setProperty("https.proxyPort",
+                        (new Integer(proxy.getLocalPort())).toString() );
+
+            makeHttpCall();
+
+            if (httpTrans.hasBadRequest) {
+                throw new RuntimeException("Test failed : bad http request");
+            }
+        } finally {
+            if (proxy != null) {
+                proxy.terminate();
+            }
+            if (server != null) {
+               server.terminate();
+            }
+            HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
+        }
+    }
+
+    /*
+     * Where do we find the keystores for ssl?
+     */
+    static String pathToStores = "../../../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+    public static boolean setupEnv() throws Exception {
+        firstNonLoAddress = getNonLoAddress();
+        if (firstNonLoAddress == null) {
+            System.err.println("The test needs at least one non-loopback address to run. Quit now.");
+            return false;
+        }
+        System.out.println(firstNonLoAddress.getHostAddress());
+        // will use proxy
+        System.setProperty( "https.proxyHost", firstNonLoAddress.getHostAddress());
+
+        // setup properties to do ssl
+        String keyFilename = System.getProperty("test.src", "./") + "/" +
+                             pathToStores + "/" + keyStoreFile;
+        String trustFilename = System.getProperty("test.src", "./") + "/" +
+                               pathToStores + "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+        HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
+        return true;
+    }
+
+    public static InetAddress getNonLoAddress() throws Exception {
+        InetAddress lh = InetAddress.getByName("localhost");
+        NetworkInterface loNIC = NetworkInterface.getByInetAddress(lh);
+
+        NetworkConfiguration nc = NetworkConfiguration.probe();
+        Optional<InetAddress> oaddr = nc.interfaces()
+                .filter(nif -> !nif.getName().equalsIgnoreCase(loNIC.getName()))
+                .flatMap(nif -> nc.addresses(nif))
+                .filter(a -> !a.isLoopbackAddress())
+                .findFirst();
+
+        return oaddr.orElseGet(() -> null);
+    }
+
+    public static void startHttpServer() throws IOException {
+        // Both the https server and the proxy let the
+        // system pick up an ephemeral port.
+        httpTrans = new SimpleHttpTransaction();
+        server = new TestHttpsServer(httpTrans, 1, 10, 0);
+        proxy = new TunnelProxy(1, 10, 0);
+    }
+
+    public static void makeHttpCall() throws Exception {
+        System.out.println("https server listen on: " + server.getLocalPort());
+        System.out.println("https proxy listen on: " + proxy.getLocalPort());
+        URL url = new URL("https" , firstNonLoAddress.getHostAddress(),
+                            server.getLocalPort(), "/");
+        HttpURLConnection uc = (HttpURLConnection)url.openConnection();
+        System.out.println(uc.getResponseCode());
+        uc.disconnect();
+    }
+
+    static class NameVerifier implements HostnameVerifier {
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    }
+}
+
+class SimpleHttpTransaction implements HttpCallback {
+    public boolean hasBadRequest = false;
+
+    /*
+     * Our http server which simply redirect first call
+     */
+    public void request(HttpTransaction trans) {
+        try {
+            String path = trans.getRequestURI().getPath();
+            if (path.equals("/")) {
+                // the first call, redirect it
+                String location = "/redirect";
+                trans.addResponseHeader("Location", location);
+                trans.sendResponse(302, "Moved Temporarily");
+            } else {
+                // if the bug exsits, it'll send 2 GET commands
+                // check 2nd GET here
+                String duplicatedGet = trans.getRequestHeader(null);
+                if (duplicatedGet != null &&
+                    duplicatedGet.toUpperCase().indexOf("GET") >= 0) {
+                    trans.sendResponse(400, "Bad Request");
+                    hasBadRequest = true;
+                } else {
+                    trans.sendResponse(200, "OK");
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/HttpsURLConnection/ReadTimeout.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4811482 4700777 4905410
+ * @summary sun.net.client.defaultConnectTimeout should work with
+ *     HttpsURLConnection; HTTP client: Connect and read timeouts;
+ *     Https needs to support new tiger features that went into http
+ * @run main/othervm ReadTimeout
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class ReadTimeout {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Message posted
+     */
+    static String postMsg = "Testing HTTP post on a https server";
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+        try {
+            try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+                InputStream sslIS = sslSocket.getInputStream();
+                BufferedReader br =
+                        new BufferedReader(new InputStreamReader(sslIS));
+                br.readLine();
+                while (!finished())  {
+                    Thread.sleep(2000);
+                }
+            }
+
+            reset();
+            // doing second test
+            try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+                InputStream sslIS = sslSocket.getInputStream();
+                BufferedReader br =
+                        new BufferedReader(new InputStreamReader(sslIS));
+                br.readLine();
+                while (!finished())  {
+                    Thread.sleep(2000);
+                }
+            }
+        } catch (Exception e) {
+            System.out.println("Should be an expected exception: " + e);
+        } finally {
+            sslServerSocket.close();
+        }
+    }
+
+    boolean isFinished = false;
+
+    synchronized boolean finished () {
+        return (isFinished);
+    }
+    synchronized void done () {
+        isFinished = true;
+    }
+
+    synchronized void reset() {
+        isFinished = false;
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        HostnameVerifier reservedHV =
+            HttpsURLConnection.getDefaultHostnameVerifier();
+        try {
+            /*
+             * Wait for server to get started.
+             */
+            while (!serverReady) {
+                Thread.sleep(50);
+            }
+            HttpsURLConnection http = null;
+            try {
+                URL url = new URL("https://localhost:" + serverPort);
+
+                // set read timeout through system property
+                System.setProperty("sun.net.client.defaultReadTimeout", "2000");
+                HttpsURLConnection.setDefaultHostnameVerifier(
+                                          new NameVerifier());
+                http = (HttpsURLConnection)url.openConnection();
+
+                InputStream is = http.getInputStream();
+
+                throw new Exception(
+                        "system property timeout configuration does not work");
+            } catch (SSLException | SocketTimeoutException ex) {
+                System.out.println("Got expected timeout exception for " +
+                        "system property timeout configuration: " + getCause(ex));
+            } finally {
+                done();
+                http.disconnect();
+            }
+
+            try {
+                URL url = new URL("https://localhost:" + serverPort);
+
+                HttpsURLConnection.setDefaultHostnameVerifier(
+                                          new NameVerifier());
+                http = (HttpsURLConnection)url.openConnection();
+                // set read timeout through API
+                http.setReadTimeout(2000);
+
+                InputStream is = http.getInputStream();
+
+                throw new Exception(
+                        "HttpsURLConnection.setReadTimeout() does not work");
+            } catch (SSLException | SocketTimeoutException ex) {
+                System.out.println("Got expected timeout exception for " +
+                        "HttpsURLConnection.setReadTimeout(): " + getCause(ex));
+            } finally {
+                done();
+                http.disconnect();
+            }
+        } finally {
+            HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
+        }
+    }
+
+    private Exception getCause(Exception ex) {
+        Exception cause = null;
+        if (ex instanceof SSLException) {
+            cause = (Exception) ex.getCause();
+            if (!(cause instanceof SocketTimeoutException)) {
+                throw new RuntimeException("Unexpected cause", cause);
+            }
+        } else {
+            cause = ex;
+        }
+
+        return cause;
+    }
+
+    static class NameVerifier implements HostnameVerifier {
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ReadTimeout();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ReadTimeout() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null)
+            throw serverException;
+        if (clientException != null)
+            throw clientException;
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/NewImpl/ComHTTPSConnection.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,393 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4474255
+ * @summary Can no longer obtain a com.sun.net.ssl.HttpsURLConnection
+ * @modules java.base/com.sun.net.ssl
+ *          java.base/com.sun.net.ssl.internal.www.protocol.https
+ * @run main/othervm ComHTTPSConnection
+ *
+ *     SunJSSE does not support dynamic system properties, no way to re-use
+ *     system properties in samevm/agentvm mode.
+ * @author Brad Wetmore
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.cert.Certificate;
+import javax.net.ssl.*;
+import com.sun.net.ssl.HostnameVerifier;
+import com.sun.net.ssl.HttpsURLConnection;
+
+/**
+ * See if we can obtain a com.sun.net.ssl.HttpsURLConnection,
+ * and then play with it a bit.
+ */
+public class ComHTTPSConnection {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /**
+     * Returns the path to the file obtained from
+     * parsing the HTML header.
+     */
+    private static String getPath(DataInputStream in)
+        throws IOException
+    {
+        String line = in.readLine();
+        String path = "";
+        // extract class from GET line
+        if (line.startsWith("GET /")) {
+            line = line.substring(5, line.length()-1).trim();
+            int index = line.indexOf(' ');
+            if (index != -1) {
+                path = line.substring(0, index);
+            }
+        }
+
+        // eat the rest of header
+        do {
+            line = in.readLine();
+        } while ((line.length() != 0) &&
+                 (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
+
+        if (path.length() != 0) {
+            return path;
+        } else {
+            throw new IOException("Malformed Header");
+        }
+    }
+
+    /**
+     * Returns an array of bytes containing the bytes for
+     * the file represented by the argument <b>path</b>.
+     *
+     * In our case, we just pretend to send something back.
+     *
+     * @return the bytes for the file
+     * @exception FileNotFoundException if the file corresponding
+     * to <b>path</b> could not be loaded.
+     */
+    private byte[] getBytes(String path)
+        throws IOException
+    {
+        return "Hello world, I am here".getBytes();
+    }
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+
+        SSLServerSocketFactory sslssf =
+          (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        DataOutputStream out =
+                new DataOutputStream(sslSocket.getOutputStream());
+
+        try {
+             // get path to class file from header
+             DataInputStream in =
+                        new DataInputStream(sslSocket.getInputStream());
+             String path = getPath(in);
+             // retrieve bytecodes
+             byte[] bytecodes = getBytes(path);
+             // send bytecodes in response (assumes HTTP/1.0 or later)
+             try {
+                out.writeBytes("HTTP/1.0 200 OK\r\n");
+                out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
+                out.writeBytes("Content-Type: text/html\r\n\r\n");
+                out.write(bytecodes);
+                out.flush();
+             } catch (IOException ie) {
+                ie.printStackTrace();
+                return;
+             }
+
+        } catch (Exception e) {
+             e.printStackTrace();
+             // write out error response
+             out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
+             out.writeBytes("Content-Type: text/html\r\n\r\n");
+             out.flush();
+        } finally {
+             // close the socket
+             System.out.println("Server closing socket");
+             sslSocket.close();
+             serverReady = false;
+        }
+    }
+
+    private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory {
+        private static String SUPPORTED_PROTOCOL = "https";
+
+        public URLStreamHandler createURLStreamHandler(String protocol) {
+            if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL))
+                return null;
+
+            return new com.sun.net.ssl.internal.www.protocol.https.Handler();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        HostnameVerifier reservedHV =
+            HttpsURLConnection.getDefaultHostnameVerifier();
+        try {
+            URL.setURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory());
+            HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
+
+            URL url = new URL("https://" + "localhost:" + serverPort +
+                                    "/etc/hosts");
+            URLConnection urlc = url.openConnection();
+
+            if (!(urlc instanceof com.sun.net.ssl.HttpsURLConnection)) {
+                throw new Exception(
+                    "URLConnection ! instanceof " +
+                    "com.sun.net.ssl.HttpsURLConnection");
+            }
+
+            BufferedReader in = null;
+            try {
+                in = new BufferedReader(new InputStreamReader(
+                                   urlc.getInputStream()));
+                String inputLine;
+                System.out.print("Client reading... ");
+                while ((inputLine = in.readLine()) != null)
+                    System.out.println(inputLine);
+
+                System.out.println("Cipher Suite: " +
+                    ((HttpsURLConnection)urlc).getCipherSuite());
+                Certificate[] certs =
+                    ((HttpsURLConnection)urlc).getServerCertificates();
+                for (int i = 0; i < certs.length; i++) {
+                    System.out.println(certs[0]);
+                }
+
+                in.close();
+            } catch (SSLException e) {
+                if (in != null)
+                    in.close();
+                throw e;
+            }
+            System.out.println("Client reports:  SUCCESS");
+        } finally {
+            HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
+        }
+    }
+
+    static class NameVerifier implements HostnameVerifier {
+        public boolean verify(String urlHostname,
+                        String certHostname) {
+            System.out.println(
+                "CertificateHostnameVerifier: " + urlHostname + " == "
+                + certHostname + " returning true");
+            return true;
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ComHTTPSConnection();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ComHTTPSConnection() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/net/www/protocol/https/NewImpl/ComHostnameVerifier.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 4474255 4484246
+ * @summary When an application enables anonymous SSL cipher suite,
+ *        Hostname verification is not required
+ * @modules java.base/com.sun.net.ssl
+ *          java.base/com.sun.net.ssl.internal.www.protocol.https
+ * @run main/othervm ComHostnameVerifier
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.Security;
+import javax.net.ssl.*;
+import javax.security.cert.*;
+import com.sun.net.ssl.HostnameVerifier;
+import com.sun.net.ssl.HttpsURLConnection;
+
+/**
+ * Use com.net.net.ssl.HostnameVerifier
+ */
+public class ComHostnameVerifier {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /**
+     * Returns the path to the file obtained from
+     * parsing the HTML header.
+     */
+    private static String getPath(DataInputStream in)
+        throws IOException
+    {
+        String line = in.readLine();
+        if (line == null)
+                return null;
+        String path = "";
+        // extract class from GET line
+        if (line.startsWith("GET /")) {
+            line = line.substring(5, line.length()-1).trim();
+            int index = line.indexOf(' ');
+            if (index != -1) {
+                path = line.substring(0, index);
+            }
+        }
+
+        // eat the rest of header
+        do {
+            line = in.readLine();
+        } while ((line.length() != 0) &&
+                 (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
+
+        if (path.length() != 0) {
+            return path;
+        } else {
+            throw new IOException("Malformed Header");
+        }
+    }
+
+    /**
+     * Returns an array of bytes containing the bytes for
+     * the file represented by the argument <b>path</b>.
+     *
+     * In our case, we just pretend to send something back.
+     *
+     * @return the bytes for the file
+     * @exception FileNotFoundException if the file corresponding
+     * to <b>path</b> could not be loaded.
+     */
+    private byte[] getBytes(String path)
+        throws IOException
+    {
+        return "Hello world, I am here".getBytes();
+    }
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+
+        SSLServerSocketFactory sslssf =
+          (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        String ciphers[]= { "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA" };
+        sslServerSocket.setEnabledCipherSuites(ciphers);
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        DataOutputStream out =
+                new DataOutputStream(sslSocket.getOutputStream());
+
+        try {
+             // get path to class file from header
+             DataInputStream in =
+                        new DataInputStream(sslSocket.getInputStream());
+             String path = getPath(in);
+             // retrieve bytecodes
+             byte[] bytecodes = getBytes(path);
+             // send bytecodes in response (assumes HTTP/1.0 or later)
+             try {
+                out.writeBytes("HTTP/1.0 200 OK\r\n");
+                out.writeBytes("Content-Length: " + bytecodes.length + "\r\n");
+                out.writeBytes("Content-Type: text/html\r\n\r\n");
+                out.write(bytecodes);
+                out.flush();
+             } catch (IOException ie) {
+                ie.printStackTrace();
+                return;
+             }
+
+        } catch (Exception e) {
+             e.printStackTrace();
+             // write out error response
+             out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
+             out.writeBytes("Content-Type: text/html\r\n\r\n");
+             out.flush();
+        } finally {
+             // close the socket
+             System.out.println("Server closing socket");
+             sslSocket.close();
+             serverReady = false;
+        }
+    }
+
+    private static class ComSunHTTPSHandlerFactory implements URLStreamHandlerFactory {
+        private static String SUPPORTED_PROTOCOL = "https";
+
+        public URLStreamHandler createURLStreamHandler(String protocol) {
+            if (!protocol.equalsIgnoreCase(SUPPORTED_PROTOCOL))
+                return null;
+
+            return new com.sun.net.ssl.internal.www.protocol.https.Handler();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        URL.setURLStreamHandlerFactory(new ComSunHTTPSHandlerFactory());
+
+        System.setProperty("https.cipherSuites",
+                "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA");
+
+        // use the default hostname verifier
+
+        URL url = new URL("https://" + "localhost:" + serverPort +
+                                "/etc/hosts");
+        URLConnection urlc = url.openConnection();
+
+        if (!(urlc instanceof com.sun.net.ssl.HttpsURLConnection)) {
+            throw new Exception(
+                "URLConnection ! instanceof " +
+                "com.sun.net.ssl.HttpsURLConnection");
+        }
+
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new InputStreamReader(
+                               urlc.getInputStream()));
+            String inputLine;
+            System.out.print("Client reading... ");
+            while ((inputLine = in.readLine()) != null)
+                System.out.println(inputLine);
+            System.out.println("Cipher Suite: " +
+                ((HttpsURLConnection)urlc).getCipherSuite());
+            in.close();
+        } catch (SSLException e) {
+            if (in != null)
+                in.close();
+            throw e;
+        }
+        System.out.println("Client reports:  SUCCESS");
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        // re-enable 3DES
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ComHostnameVerifier();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ComHostnameVerifier() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/pkcs11/sslecc/CipherTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import java.security.*;
+import java.security.cert.*;
+
+import javax.net.ssl.*;
+
+/**
+ * Test that all ciphersuites work in all versions and all client
+ * authentication types. The way this is setup the server is stateless and
+ * all checking is done on the client side.
+ *
+ * The test is multithreaded to speed it up, especially on multiprocessor
+ * machines. To simplify debugging, run with -DnumThreads=1.
+ *
+ * @author Andreas Sterbenz
+ */
+public class CipherTest {
+
+    // use any available port for the server socket
+    static volatile int serverPort = 0;
+
+    static final int THREADS = Integer.getInteger("numThreads", 4);
+    static final String TEST_SRC = System.getProperty("test.src", ".");
+
+    // assume that if we do not read anything for 20 seconds, something
+    // has gone wrong
+    final static int TIMEOUT = 20 * 1000;
+
+    static KeyStore trustStore, keyStore;
+    static X509ExtendedKeyManager keyManager;
+    static X509TrustManager trustManager;
+    static SecureRandom secureRandom;
+
+    private static PeerFactory peerFactory;
+
+    static final CountDownLatch clientCondition = new CountDownLatch(1);
+
+    static abstract class Server implements Runnable {
+
+        final CipherTest cipherTest;
+
+        Server(CipherTest cipherTest) throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        @Override
+        public abstract void run();
+
+        void handleRequest(InputStream in, OutputStream out) throws IOException {
+            boolean newline = false;
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                int ch = in.read();
+                if (ch < 0) {
+                    throw new EOFException();
+                }
+                sb.append((char)ch);
+                if (ch == '\r') {
+                    // empty
+                } else if (ch == '\n') {
+                    if (newline) {
+                        // 2nd newline in a row, end of request
+                        break;
+                    }
+                    newline = true;
+                } else {
+                    newline = false;
+                }
+            }
+            String request = sb.toString();
+            if (request.startsWith("GET / HTTP/1.") == false) {
+                throw new IOException("Invalid request: " + request);
+            }
+            out.write("HTTP/1.0 200 OK\r\n\r\n".getBytes());
+        }
+
+    }
+
+    public static class TestParameters {
+
+        CipherSuite cipherSuite;
+        Protocol protocol;
+        String clientAuth;
+
+        TestParameters(CipherSuite cipherSuite, Protocol protocol,
+                String clientAuth) {
+            this.cipherSuite = cipherSuite;
+            this.protocol = protocol;
+            this.clientAuth = clientAuth;
+        }
+
+        boolean isEnabled() {
+            return cipherSuite.supportedByProtocol(protocol);
+        }
+
+        @Override
+        public String toString() {
+            String s = cipherSuite + " in " + protocol + " mode";
+            if (clientAuth != null) {
+                s += " with " + clientAuth + " client authentication";
+            }
+            return s;
+        }
+    }
+
+    private List<TestParameters> tests;
+    private Iterator<TestParameters> testIterator;
+    private SSLSocketFactory factory;
+    private boolean failed;
+
+    private CipherTest(PeerFactory peerFactory) throws IOException {
+        factory = (SSLSocketFactory)SSLSocketFactory.getDefault();
+        SSLSocket socket = (SSLSocket)factory.createSocket();
+        String[] cipherSuites = socket.getSupportedCipherSuites();
+        String[] protocols = socket.getSupportedProtocols();
+        String[] clientAuths = {null, "RSA", "DSA", "ECDSA"};
+        tests = new ArrayList<TestParameters>(
+            cipherSuites.length * protocols.length * clientAuths.length);
+        for (int i = 0; i < cipherSuites.length; i++) {
+            String cipherSuite = cipherSuites[i];
+
+            for (int j = 0; j < protocols.length; j++) {
+                String protocol = protocols[j];
+
+                if (!peerFactory.isSupported(cipherSuite, protocol)) {
+                    continue;
+                }
+
+                for (int k = 0; k < clientAuths.length; k++) {
+                    String clientAuth = clientAuths[k];
+                    // no client with anonymous cipher suites.
+                    // TLS_EMPTY_RENEGOTIATION_INFO_SCSV always be skipped.
+                    // TLS 1.3 is skipped due to the signature algorithm,
+                    // exactly MD5withRSA, in the certificates is not allowed.
+                    if ((clientAuth != null && cipherSuite.contains("DH_anon")
+                            || cipherSuite.equals(
+                                    CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV.name())
+                            || "TLSv1.3".equals(protocol))) {
+                        continue;
+                    }
+
+                    tests.add(new TestParameters(
+                            CipherSuite.cipherSuite(cipherSuite),
+                            Protocol.protocol(protocol),
+                            clientAuth));
+                }
+            }
+        }
+
+        testIterator = tests.iterator();
+    }
+
+    synchronized void setFailed() {
+        failed = true;
+    }
+
+    public void run() throws Exception {
+        Thread[] threads = new Thread[THREADS];
+        for (int i = 0; i < THREADS; i++) {
+            try {
+                threads[i] = new Thread(peerFactory.newClient(this),
+                    "Client " + i);
+            } catch (Exception e) {
+                e.printStackTrace();
+                return;
+            }
+            threads[i].start();
+        }
+
+        // The client threads are ready.
+        clientCondition.countDown();
+
+        try {
+            for (int i = 0; i < THREADS; i++) {
+                threads[i].join();
+            }
+        } catch (InterruptedException e) {
+            setFailed();
+            e.printStackTrace();
+        }
+        if (failed) {
+            throw new Exception("*** Test '" + peerFactory.getName() +
+                "' failed ***");
+        } else {
+            System.out.println("Test '" + peerFactory.getName() +
+                "' completed successfully");
+        }
+    }
+
+    synchronized TestParameters getTest() {
+        if (failed) {
+            return null;
+        }
+        if (testIterator.hasNext()) {
+            return (TestParameters)testIterator.next();
+        }
+        return null;
+    }
+
+    SSLSocketFactory getFactory() {
+        return factory;
+    }
+
+    static abstract class Client implements Runnable {
+
+        final CipherTest cipherTest;
+
+        Client(CipherTest cipherTest) throws Exception {
+            this.cipherTest = cipherTest;
+        }
+
+        @Override
+        public final void run() {
+            while (true) {
+                TestParameters params = cipherTest.getTest();
+                if (params == null) {
+                    // no more tests
+                    break;
+                }
+                if (params.isEnabled() == false) {
+                    System.out.println("Skipping disabled test " + params);
+                    continue;
+                }
+                try {
+                    runTest(params);
+                    System.out.println("Passed " + params);
+                } catch (SocketTimeoutException ste) {
+                    System.out.println("The client connects to the server timeout, "
+                            + "so ignore the test.");
+                    break;
+                } catch (Exception e) {
+                    cipherTest.setFailed();
+                    System.out.println("** Failed " + params + "**");
+                    e.printStackTrace();
+                }
+            }
+        }
+
+        abstract void runTest(TestParameters params) throws Exception;
+
+        void sendRequest(InputStream in, OutputStream out) throws IOException {
+            out.write("GET / HTTP/1.0\r\n\r\n".getBytes());
+            out.flush();
+            StringBuilder sb = new StringBuilder();
+            while (true) {
+                int ch = in.read();
+                if (ch < 0) {
+                    break;
+                }
+                sb.append((char)ch);
+            }
+            String response = sb.toString();
+            if (response.startsWith("HTTP/1.0 200 ") == false) {
+                throw new IOException("Invalid response: " + response);
+            }
+        }
+
+    }
+
+    // for some reason, ${test.src} has a different value when the
+    // test is called from the script and when it is called directly...
+    static String pathToStores = ".";
+    static String pathToStoresSH = ".";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static char[] passwd = "passphrase".toCharArray();
+
+    static File PATH;
+
+    private static KeyStore readKeyStore(String name) throws Exception {
+        File file = new File(PATH, name);
+        KeyStore ks;
+        try (InputStream in = new FileInputStream(file)) {
+            ks = KeyStore.getInstance("JKS");
+            ks.load(in, passwd);
+        }
+        return ks;
+    }
+
+    public static void main(PeerFactory peerFactory, String[] args)
+            throws Exception {
+        long time = System.currentTimeMillis();
+        String relPath;
+        if ((args != null) && (args.length > 0) && args[0].equals("sh")) {
+            relPath = pathToStoresSH;
+        } else {
+            relPath = pathToStores;
+        }
+        PATH = new File(TEST_SRC, relPath);
+        CipherTest.peerFactory = peerFactory;
+        System.out.print(
+            "Initializing test '" + peerFactory.getName() + "'...");
+        secureRandom = new SecureRandom();
+        secureRandom.nextInt();
+        trustStore = readKeyStore(trustStoreFile);
+        keyStore = readKeyStore(keyStoreFile);
+        KeyManagerFactory keyFactory =
+            KeyManagerFactory.getInstance(
+                KeyManagerFactory.getDefaultAlgorithm());
+        keyFactory.init(keyStore, passwd);
+        keyManager = (X509ExtendedKeyManager)keyFactory.getKeyManagers()[0];
+        trustManager = new AlwaysTrustManager();
+
+        CipherTest cipherTest = new CipherTest(peerFactory);
+        Thread serverThread = new Thread(peerFactory.newServer(cipherTest),
+            "Server");
+        serverThread.setDaemon(true);
+        serverThread.start();
+        System.out.println("Done");
+        cipherTest.run();
+        time = System.currentTimeMillis() - time;
+        System.out.println("Done. (" + time + " ms)");
+    }
+
+    static abstract class PeerFactory {
+
+        abstract String getName();
+
+        abstract Client newClient(CipherTest cipherTest) throws Exception;
+
+        abstract Server newServer(CipherTest cipherTest) throws Exception;
+
+        boolean isSupported(String cipherSuite, String protocol) {
+            // skip kerberos cipher suites
+            if (cipherSuite.startsWith("TLS_KRB5")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // skip SSLv2Hello protocol
+            if (protocol.equals("SSLv2Hello")) {
+                System.out.println("Skipping unsupported test for " +
+                                    cipherSuite + " of " + protocol);
+                return false;
+            }
+
+            // ignore exportable cipher suite for TLSv1.1
+            if (protocol.equals("TLSv1.1")) {
+                if (cipherSuite.indexOf("_EXPORT_WITH") != -1) {
+                    System.out.println("Skipping obsoleted test for " +
+                                        cipherSuite + " of " + protocol);
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    }
+
+}
+
+// we currently don't do any chain verification. we assume that works ok
+// and we can speed up the test. we could also just add a plain certificate
+// chain comparision with our trusted certificates.
+class AlwaysTrustManager implements X509TrustManager {
+
+    public AlwaysTrustManager() {
+
+    }
+
+    @Override
+    public void checkClientTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        // empty
+    }
+
+    @Override
+    public void checkServerTrusted(X509Certificate[] chain, String authType)
+            throws CertificateException {
+        // empty
+    }
+
+    @Override
+    public X509Certificate[] getAcceptedIssuers() {
+        return new X509Certificate[0];
+    }
+}
+
+class MyX509KeyManager extends X509ExtendedKeyManager {
+
+    private final X509ExtendedKeyManager keyManager;
+    private String authType;
+
+    MyX509KeyManager(X509ExtendedKeyManager keyManager) {
+        this.keyManager = keyManager;
+    }
+
+    void setAuthType(String authType) {
+        this.authType = "ECDSA".equals(authType) ? "EC" : authType;
+    }
+
+    @Override
+    public String[] getClientAliases(String keyType, Principal[] issuers) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.getClientAliases(authType, issuers);
+    }
+
+    @Override
+    public String chooseClientAlias(String[] keyType, Principal[] issuers,
+            Socket socket) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.chooseClientAlias(new String[] {authType},
+            issuers, socket);
+    }
+
+    @Override
+    public String chooseEngineClientAlias(String[] keyType,
+            Principal[] issuers, SSLEngine engine) {
+        if (authType == null) {
+            return null;
+        }
+        return keyManager.chooseEngineClientAlias(new String[] {authType},
+            issuers, engine);
+    }
+
+    @Override
+    public String[] getServerAliases(String keyType, Principal[] issuers) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    @Override
+    public String chooseServerAlias(String keyType, Principal[] issuers,
+            Socket socket) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    @Override
+    public String chooseEngineServerAlias(String keyType, Principal[] issuers,
+            SSLEngine engine) {
+        throw new UnsupportedOperationException("Servers not supported");
+    }
+
+    @Override
+    public X509Certificate[] getCertificateChain(String alias) {
+        return keyManager.getCertificateChain(alias);
+    }
+
+    @Override
+    public PrivateKey getPrivateKey(String alias) {
+        return keyManager.getPrivateKey(alias);
+    }
+
+}
+
+class DaemonThreadFactory implements ThreadFactory {
+
+    final static ThreadFactory INSTANCE = new DaemonThreadFactory();
+
+    private final static ThreadFactory DEFAULT = Executors.defaultThreadFactory();
+
+    @Override
+    public Thread newThread(Runnable r) {
+        Thread t = DEFAULT.newThread(r);
+        t.setDaemon(true);
+        return t;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 6405536
+ * @summary Verify that all ciphersuites work (incl. ECC using NSS crypto)
+ * @author Andreas Sterbenz
+ * @library /test/lib .. ../../../../javax/net/ssl/TLSCommon
+ * @library ../../../../java/security/testlibrary
+ * @modules jdk.crypto.cryptoki
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
+ *      ClientJSSEServerJSSE
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
+ *      ClientJSSEServerJSSE sm policy
+ */
+
+import java.security.Provider;
+import java.security.Security;
+
+public class ClientJSSEServerJSSE extends PKCS11Test {
+
+    private static String[] cmdArgs;
+
+    public static void main(String[] args) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        cmdArgs = args;
+        main(new ClientJSSEServerJSSE(), args);
+    }
+
+    @Override
+    public void main(Provider p) throws Exception {
+        if (p.getService("KeyFactory", "EC") == null) {
+            System.out.println("Provider does not support EC, skipping");
+            return;
+        }
+        Providers.setAt(p, 1);
+        CipherTest.main(new JSSEFactory(), cmdArgs);
+        Security.removeProvider(p.getName());
+    }
+
+    private static class JSSEFactory extends CipherTest.PeerFactory {
+
+        @Override
+        String getName() {
+            return "Client JSSE - Server JSSE";
+        }
+
+        @Override
+        CipherTest.Client newClient(CipherTest cipherTest) throws Exception {
+            return new JSSEClient(cipherTest);
+        }
+
+        @Override
+        CipherTest.Server newServer(CipherTest cipherTest) throws Exception {
+            return new JSSEServer(cipherTest);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/pkcs11/sslecc/JSSEClient.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2002, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.net.*;
+
+import java.security.cert.Certificate;
+
+import javax.net.ssl.*;
+
+class JSSEClient extends CipherTest.Client {
+
+    private final SSLContext sslContext;
+    private final MyX509KeyManager keyManager;
+
+    JSSEClient(CipherTest cipherTest) throws Exception {
+        super(cipherTest);
+        this.keyManager = new MyX509KeyManager(CipherTest.keyManager);
+        sslContext = SSLContext.getInstance("TLS");
+    }
+
+    void runTest(CipherTest.TestParameters params) throws Exception {
+        SSLSocket socket = null;
+        try {
+            keyManager.setAuthType(params.clientAuth);
+            sslContext.init(
+                    new KeyManager[] { keyManager },
+                    new TrustManager[] { CipherTest.trustManager },
+                    CipherTest.secureRandom);
+            SSLSocketFactory factory
+                    = (SSLSocketFactory) sslContext.getSocketFactory();
+
+            socket = (SSLSocket) factory.createSocket();
+            try {
+                socket.connect(new InetSocketAddress("127.0.0.1",
+                        CipherTest.serverPort), 15000);
+            } catch (IOException ioe) {
+                // The server side may be impacted by naughty test cases or
+                // third party routines, and cannot accept connections.
+                //
+                // Just ignore the test if the connection cannot be
+                // established.
+                System.out.println(
+                        "Cannot make a connection in 15 seconds. " +
+                        "Ignore in client side.");
+                return;
+            }
+
+            socket.setSoTimeout(CipherTest.TIMEOUT);
+            socket.setEnabledCipherSuites(new String[] {params.cipherSuite.name()});
+            socket.setEnabledProtocols(new String[] {params.protocol.name});
+            InputStream in = socket.getInputStream();
+            OutputStream out = socket.getOutputStream();
+            sendRequest(in, out);
+            socket.close();
+            SSLSession session = socket.getSession();
+            session.invalidate();
+            String cipherSuite = session.getCipherSuite();
+            if (!params.cipherSuite.name().equals(cipherSuite)) {
+                throw new Exception("Negotiated ciphersuite mismatch: " + cipherSuite + " != " + params.cipherSuite);
+            }
+            String protocol = session.getProtocol();
+            if (!params.protocol.name.equals(protocol)) {
+                throw new Exception("Negotiated protocol mismatch: " + protocol + " != " + params.protocol);
+            }
+            if (cipherSuite.indexOf("DH_anon") == -1) {
+                session.getPeerCertificates();
+            }
+            Certificate[] certificates = session.getLocalCertificates();
+            if (params.clientAuth == null) {
+                if (certificates != null) {
+                    throw new Exception("Local certificates should be null");
+                }
+            } else {
+                if ((certificates == null) || (certificates.length == 0)) {
+                    throw new Exception("Certificates missing");
+                }
+                String keyAlg = certificates[0].getPublicKey().getAlgorithm();
+                if (keyAlg.equals("EC")) {
+                    keyAlg = "ECDSA";
+                }
+                if (params.clientAuth != keyAlg) {
+                    throw new Exception("Certificate type mismatch: " + keyAlg + " != " + params.clientAuth);
+                }
+            }
+        } finally {
+            if (socket != null) {
+                socket.close();
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/pkcs11/sslecc/JSSEServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2002, 2017, 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.
+ *
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketTimeoutException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+class JSSEServer extends CipherTest.Server {
+
+    SSLServerSocket serverSocket;
+
+    JSSEServer(CipherTest cipherTest) throws Exception {
+        super(cipherTest);
+        SSLContext serverContext = SSLContext.getInstance("TLS");
+        serverContext.init(
+                new KeyManager[] { CipherTest.keyManager },
+                new TrustManager[] { CipherTest.trustManager },
+                CipherTest.secureRandom);
+
+        SSLServerSocketFactory factory = (SSLServerSocketFactory)serverContext.getServerSocketFactory();
+        serverSocket = (SSLServerSocket)factory.createServerSocket(0);
+        serverSocket.setSoTimeout(CipherTest.TIMEOUT);
+        CipherTest.serverPort = serverSocket.getLocalPort();
+        serverSocket.setEnabledCipherSuites(factory.getSupportedCipherSuites());
+        serverSocket.setWantClientAuth(true);
+    }
+
+    @Override
+    public void run() {
+        System.out.println("JSSE Server listening on port " + CipherTest.serverPort);
+        Executor exec = Executors.newFixedThreadPool
+                            (CipherTest.THREADS, DaemonThreadFactory.INSTANCE);
+
+        try {
+            if (!CipherTest.clientCondition.await(CipherTest.TIMEOUT,
+                    TimeUnit.MILLISECONDS)) {
+                System.out.println(
+                        "The client is not the expected one or timeout. "
+                                + "Ignore in server side.");
+                return;
+            }
+
+            while (true) {
+                final SSLSocket socket = (SSLSocket)serverSocket.accept();
+                socket.setSoTimeout(CipherTest.TIMEOUT);
+                Runnable r = new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            InputStream in = socket.getInputStream();
+                            OutputStream out = socket.getOutputStream();
+                            handleRequest(in, out);
+                            out.flush();
+                            socket.close();
+                            socket.getSession().invalidate();
+                        } catch (IOException e) {
+                            cipherTest.setFailed();
+                            e.printStackTrace();
+                        } finally {
+                            if (socket != null) {
+                                try {
+                                    socket.close();
+                                } catch (IOException e) {
+                                    cipherTest.setFailed();
+                                    System.out.println("Exception closing socket on server side:");
+                                    e.printStackTrace();
+                                }
+                            }
+                        }
+                    }
+                };
+                exec.execute(r);
+            }
+        } catch (SocketTimeoutException ste) {
+            System.out.println("The server got timeout for waiting for the connection, "
+                    + "so ignore the test.");
+        } catch (Exception e) {
+            cipherTest.setFailed();
+            e.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/pkcs11/sslecc/policy	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,9 @@
+grant {
+    permission java.lang.RuntimePermission "setSecurityManager";
+    permission java.security.SecurityPermission "insertProvider.*";
+    permission java.security.SecurityPermission "removeProvider.*";
+    permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "numThreads", "read";
+    permission java.io.FilePermission "${test.src}/*", "read";
+    permission java.net.SocketPermission "127.0.0.1:*", "listen,resolve,accept,connect";
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/provider/certpath/Extensions/OCSPNonceExtensionTests.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,369 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8046321
+ * @summary Unit tests for OCSPNonceExtension objects
+ * @modules java.base/sun.security.provider.certpath
+ *          java.base/sun.security.util
+ *          java.base/sun.security.x509
+ */
+
+import java.security.cert.Extension;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.*;
+
+import sun.security.util.DerValue;
+import sun.security.util.DerInputStream;
+import sun.security.util.ObjectIdentifier;
+import sun.security.provider.certpath.OCSPNonceExtension;
+import sun.security.x509.PKIXExtensions;
+
+public class OCSPNonceExtensionTests {
+    public static final boolean DEBUG = true;
+    public static final String OCSP_NONCE_OID = "1.3.6.1.5.5.7.48.1.2";
+    public static final String ELEMENT_NONCE = "nonce";
+    public static final String EXT_NAME = "OCSPNonce";
+
+    // DER encoding for OCSP nonce extension:
+    // OID = 1.3.6.1.5.5.7.48.1.2
+    // Critical = true
+    // 48 bytes of 0xDEADBEEF
+    public static final byte[] OCSP_NONCE_DER = {
+          48,   66,    6,    9,   43,    6,    1,    5,
+           5,    7,   48,    1,    2,    1,    1,   -1,
+           4,   50,    4,   48,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,
+    };
+
+    // 16 bytes of 0xDEADBEEF
+    public static final byte[] DEADBEEF_16 = {
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+         -34,  -83,  -66,  -17,  -34,  -83,  -66,  -17,
+    };
+
+    // DER encoded extension using 16 bytes of DEADBEEF
+    public static final byte[] OCSP_NONCE_DB16 = {
+          48,   31,    6,    9,   43,    6,    1,    5,
+           5,    7,   48,    1,    2,    4,   18,    4,
+          16,  -34,  -83,  -66,  -17,  -34,  -83,  -66,
+         -17,  -34,  -83,  -66,  -17,  -34,  -83,  -66,
+         -17
+    };
+
+    public static void main(String [] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("CTOR Test (provide length)", testCtorByLength);
+            put("CTOR Test (provide nonce bytes)", testCtorByValue);
+            put("CTOR Test (set criticality forms)", testCtorCritForms);
+            put("CTOR Test (provide extension DER encoding)",
+                    testCtorSuperByDerValue);
+            put("Test getName() method", testGetName);
+        }};
+
+        System.out.println("============ Tests ============");
+        int testNo = 0;
+        int numberFailed = 0;
+        Map.Entry<Boolean, String> result;
+        for (String testName : testList.keySet()) {
+            System.out.println("Test " + ++testNo + ": " + testName);
+            result = testList.get(testName).runTest();
+            System.out.print("Result: " + (result.getKey() ? "PASS" : "FAIL"));
+            System.out.println(" " +
+                    (result.getValue() != null ? result.getValue() : ""));
+            System.out.println("-------------------------------------------");
+            if (!result.getKey()) {
+                numberFailed++;
+            }
+        }
+        System.out.println("End Results: " + (testList.size() - numberFailed) +
+                " Passed" + ", " + numberFailed + " Failed.");
+        if (numberFailed > 0) {
+            throw new RuntimeException(
+                    "One or more tests failed, see test output for details");
+        }
+    }
+
+    private static void dumpHexBytes(byte[] data) {
+        if (data != null) {
+            for (int i = 0; i < data.length; i++) {
+                if (i % 16 == 0 && i != 0) {
+                    System.out.print("\n");
+                }
+                System.out.print(String.format("%02X ", data[i]));
+            }
+            System.out.print("\n");
+        }
+    }
+
+    private static void debuglog(String message) {
+        if (DEBUG) {
+            System.out.println(message);
+        }
+    }
+
+    public static void verifyExtStructure(byte[] derData) throws IOException {
+        debuglog("verifyASN1Extension() received " + derData.length + " bytes");
+        DerInputStream dis = new DerInputStream(derData);
+
+        // The sequenceItems array should be either two or three elements
+        // long.  If three, then the criticality bit setting has been asserted.
+        DerValue[] sequenceItems = dis.getSequence(3);
+        debuglog("Found sequence containing " + sequenceItems.length +
+                " elements");
+        if (sequenceItems.length != 2 && sequenceItems.length != 3) {
+            throw new RuntimeException("Incorrect number of items found in " +
+                    "the SEQUENCE (Got " + sequenceItems.length +
+                    ", expected 2 or 3 items)");
+        }
+
+        int seqIndex = 0;
+        ObjectIdentifier extOid = sequenceItems[seqIndex++].getOID();
+        debuglog("Found OID: " + extOid.toString());
+        if (!extOid.equals((Object)PKIXExtensions.OCSPNonce_Id)) {
+            throw new RuntimeException("Incorrect OID (Got " +
+                    extOid.toString() + ", expected " +
+                    PKIXExtensions.OCSPNonce_Id.toString() + ")");
+        }
+
+        if (sequenceItems.length == 3) {
+            // Non-default criticality bit setting should be at index 1
+            boolean isCrit = sequenceItems[seqIndex++].getBoolean();
+            debuglog("Found BOOLEAN (critical): " + isCrit);
+        }
+
+        // The extnValue is an encapsulating OCTET STRING that contains the
+        // extension's value.  For the OCSP Nonce, that value itself is also
+        // an OCTET STRING consisting of the random bytes.
+        DerValue extnValue =
+                new DerValue(sequenceItems[seqIndex++].getOctetString());
+        byte[] nonceData = extnValue.getOctetString();
+        debuglog("Found " + nonceData.length + " bytes of nonce data");
+    }
+
+    public interface TestCase {
+        Map.Entry<Boolean, String> runTest();
+    }
+
+    public static final TestCase testCtorByLength = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+                // Try sending in a negative length
+                try {
+                    Extension negLenNonce = new OCSPNonceExtension(-8);
+                    throw new RuntimeException(
+                            "Accepted a negative length nonce");
+                } catch (IllegalArgumentException iae) { }
+
+                // How about a zero length?
+                try {
+                    Extension zeroLenNonce = new OCSPNonceExtension(0);
+                    throw new RuntimeException("Accepted a zero length nonce");
+                } catch (IllegalArgumentException iae) { }
+
+                // Valid input to constructor
+                Extension nonceByLen = new OCSPNonceExtension(32);
+
+                // Verify overall encoded extension structure
+                nonceByLen.encode(baos);
+                verifyExtStructure(baos.toByteArray());
+
+                // Verify the name, elements, and data conform to
+                // expected values for this specific object.
+                boolean crit = nonceByLen.isCritical();
+                String oid = nonceByLen.getId();
+                DerValue nonceData = new DerValue(nonceByLen.getValue());
+
+                if (crit) {
+                    message = "Extension incorrectly marked critical";
+                } else if (!oid.equals(OCSP_NONCE_OID)) {
+                    message = "Incorrect OID (Got " + oid + ", Expected " +
+                            OCSP_NONCE_OID + ")";
+                } else if (nonceData.getTag() != DerValue.tag_OctetString) {
+                    message = "Incorrect nonce data tag type (Got " +
+                            String.format("0x%02X", nonceData.getTag()) +
+                            ", Expected 0x04)";
+                } else if (nonceData.getOctetString().length != 32) {
+                    message = "Incorrect nonce byte length (Got " +
+                            nonceData.getOctetString().length +
+                            ", Expected 32)";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase testCtorByValue = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+
+                // Try giving a null value for the nonce
+                try {
+                    Extension nullNonce = new OCSPNonceExtension(null);
+                    throw new RuntimeException("Accepted a null nonce");
+                } catch (NullPointerException npe) { }
+
+                // How about a zero-length byte array?
+                try {
+                    Extension zeroLenNonce =
+                            new OCSPNonceExtension(new byte[0]);
+                    throw new RuntimeException("Accepted a zero length nonce");
+                } catch (IllegalArgumentException iae) { }
+
+                OCSPNonceExtension nonceByValue =
+                        new OCSPNonceExtension(DEADBEEF_16);
+
+                // Verify overall encoded extension structure
+                nonceByValue.encode(baos);
+                verifyExtStructure(baos.toByteArray());
+
+                // Verify the name, elements, and data conform to
+                // expected values for this specific object.
+                boolean crit = nonceByValue.isCritical();
+                String oid = nonceByValue.getId();
+                byte[] nonceData = nonceByValue.getNonceValue();
+
+                if (crit) {
+                    message = "Extension incorrectly marked critical";
+                } else if (!oid.equals(OCSP_NONCE_OID)) {
+                    message = "Incorrect OID (Got " + oid + ", Expected " +
+                            OCSP_NONCE_OID + ")";
+                } else if (!Arrays.equals(nonceData, DEADBEEF_16)) {
+                    message = "Returned nonce value did not match input";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase testCtorCritForms = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+                Extension nonceByLength = new OCSPNonceExtension(true, 32);
+                Extension nonceByValue =
+                        new OCSPNonceExtension(true, DEADBEEF_16);
+                pass = nonceByLength.isCritical() && nonceByValue.isCritical();
+                if (!pass) {
+                    message = "nonceByLength or nonceByValue was not marked " +
+                            "critical as expected";
+                }
+            }  catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+
+    public static final TestCase testCtorSuperByDerValue = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+                Extension nonceByDer = new sun.security.x509.Extension(
+                        new DerValue(OCSP_NONCE_DER));
+
+                // Verify overall encoded extension structure
+                nonceByDer.encode(baos);
+                verifyExtStructure(baos.toByteArray());
+
+                // Verify the name, elements, and data conform to
+                // expected values for this specific object.
+                boolean crit = nonceByDer.isCritical();
+                String oid = nonceByDer.getId();
+                DerValue nonceData = new DerValue(nonceByDer.getValue());
+
+                if (!crit) {
+                    message = "Extension lacks expected criticality setting";
+                } else if (!oid.equals(OCSP_NONCE_OID)) {
+                    message = "Incorrect OID (Got " + oid + ", Expected " +
+                            OCSP_NONCE_OID + ")";
+                } else if (nonceData.getTag() != DerValue.tag_OctetString) {
+                    message = "Incorrect nonce data tag type (Got " +
+                            String.format("0x%02X", nonceData.getTag()) +
+                            ", Expected 0x04)";
+                } else if (nonceData.getOctetString().length != 48) {
+                    message = "Incorrect nonce byte length (Got " +
+                            nonceData.getOctetString().length +
+                            ", Expected 48)";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase testGetName = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                OCSPNonceExtension nonceByLen = new OCSPNonceExtension(32);
+                pass = new Boolean(nonceByLen.getName().equals(EXT_NAME));
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/provider/certpath/ResponderId/ResponderIdTests.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,421 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8046321
+ * @summary OCSP Stapling for TLS (ResponderId tests)
+ * @modules java.base/sun.security.provider.certpath
+ *          java.base/sun.security.x509
+ */
+
+import java.io.*;
+import java.security.cert.*;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.util.AbstractMap;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
+import javax.security.auth.x500.X500Principal;
+import sun.security.x509.KeyIdentifier;
+import sun.security.provider.certpath.ResponderId;
+
+/*
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class ResponderIdTests {
+
+    private static final boolean debug = true;
+
+    // Source certificate created with the following command:
+    // keytool -genkeypair -alias test1 -keyalg rsa -keysize 2048 \
+    //   -validity 7300 -keystore test1.jks \
+    //   -dname "CN=SelfSignedResponder, OU=Validation Services, O=FakeCompany"
+    private static final String RESP_CERT_1 =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDQzCCAiugAwIBAgIEXTqCCjANBgkqhkiG9w0BAQsFADBSMRQwEgYDVQQKEwtG\n" +
+        "YWtlQ29tcGFueTEcMBoGA1UECxMTVmFsaWRhdGlvbiBTZXJ2aWNlczEcMBoGA1UE\n" +
+        "AxMTU2VsZlNpZ25lZFJlc3BvbmRlcjAeFw0xNDA4MTcwNDM2MzBaFw0zNDA4MTIw\n" +
+        "NDM2MzBaMFIxFDASBgNVBAoTC0Zha2VDb21wYW55MRwwGgYDVQQLExNWYWxpZGF0\n" +
+        "aW9uIFNlcnZpY2VzMRwwGgYDVQQDExNTZWxmU2lnbmVkUmVzcG9uZGVyMIIBIjAN\n" +
+        "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApt2Cmw2k9tviLxaxE8aWNuoosWKL\n" +
+        "h+K4mNcDGKSoiChsqRqeJEnOxijDZqyFwfkaXvpAduFqYjz+Lij2HumvAjHDTui6\n" +
+        "bGcbsndRDPjvVo1S7f1oWsg7oiA8Lzmjl452S7UNBsDX5Dt1e84Xxwi40B1J2y8D\n" +
+        "FRPfYRWRlC1Z4kzqkBBa7JhANS+W8KDstFZxL4AwWH/byNwB5dl2j04ohg/Ar54e\n" +
+        "mu08PIH3hmi0pAu5wn9ariA7UA5lFWRJzvgGXV5J+QVEFuvKmeJ/Q6tU5OBJGw98\n" +
+        "zjd7F5B0iE+rJHTNF1aGaQfIorz04onV2WjH2VZA18AaMwqlY2br1SBdTQIDAQAB\n" +
+        "oyEwHzAdBgNVHQ4EFgQUG09HasSTYaTIh/CxxV/rcJV1LvowDQYJKoZIhvcNAQEL\n" +
+        "BQADggEBAIcUomNpZxGkocIzzybLyeyC6vLF1k0/unuPAHZLDP3o2JTstPhLHOCg\n" +
+        "FYw1VG2i23pjwKK2x/o80tJAOmW6vowbAPnNmtNIYO3gB/ZGiKeORoGKBCRDNvFa\n" +
+        "6ZrWxwTzT3EpVwRe7ameES0uP8+S4q2P5LhwMIMw7vGHoOQJgkAh/NUiCli1qRnJ\n" +
+        "FYd6cHMJJK5gF2FqQ7tdbA26pS06bkIEvil2M5wyKKWOydOa/pr1LgMf9KxljJ8J\n" +
+        "XlAOO/mGZGkYmWnQaQuBIDyWunWYlhsyCXMa8AScgs0uUeQp19tO7R0f03q/JXoZ\n" +
+        "1At1gZiMS7SdQaRWP5q+FunAeFWjsFE=\n" +
+        "-----END CERTIFICATE-----";
+
+    private static final String RESP_CERT_1_SUBJ =
+        "CN=SelfSignedResponder, OU=Validation Services, O=FakeCompany";
+
+    private static X509Certificate cert = null;
+
+    // The expected DER-encoding for a byName ResponderId derived
+    // from RESP_CERT_1
+    private static final byte[] EXP_NAME_ID_BYTES = {
+        -95,   84,   48,   82,   49,   20,   48,   18,
+          6,    3,   85,    4,   10,   19,   11,   70,
+         97,  107,  101,   67,  111,  109,  112,   97,
+        110,  121,   49,   28,   48,   26,    6,    3,
+         85,    4,   11,   19,   19,   86,   97,  108,
+        105,  100,   97,  116,  105,  111,  110,   32,
+         83,  101,  114,  118,  105,   99,  101,  115,
+         49,   28,   48,   26,    6,    3,   85,    4,
+          3,   19,   19,   83,  101,  108,  102,   83,
+        105,  103,  110,  101,  100,   82,  101,  115,
+        112,  111,  110,  100,  101,  114
+    };
+
+    // The expected DER-encoding for a byKey ResponderId derived
+    // from RESP_CERT_1
+    private static final byte[] EXP_KEY_ID_BYTES = {
+         -94,   22,    4,   20,   27,   79,   71,  106,
+         -60, -109,   97,  -92,  -56, -121,  -16,  -79,
+         -59,   95,  -21,  112, -107,  117,   46,   -6
+    };
+
+    // The DER encoding of a byKey ResponderId, but using an
+    // incorrect explicit tagging (CONTEXT CONSTRUCTED 3)
+    private static final byte[] INV_EXPLICIT_TAG_KEY_ID = {
+         -93,   22,    4,   20,   27,   79,   71,  106,
+         -60, -109,   97,  -92,  -56, -121,  -16,  -79,
+         -59,   95,  -21,  112, -107,  117,   46,   -6
+    };
+
+    // These two ResponderId objects will have objects attached to them
+    // after the pos_CtorByName and pos_CtorByKeyId tests run.  Those
+    // two tests should always be the first two that run.
+    public static ResponderId respByName;
+    public static ResponderId respByKeyId;
+
+    public static void main(String[] args) throws Exception {
+        List<TestCase> testList = new ArrayList<>();
+
+        testList.add(pos_CtorByName);
+        testList.add(pos_CtorByKeyId);
+        testList.add(pos_CtorByEncoding);
+        testList.add(neg_CtorByEncoding);
+        testList.add(pos_Equality);
+        testList.add(pos_GetEncoded);
+        testList.add(pos_GetRespName);
+        testList.add(pos_GetRespKeyId);
+
+        // Load the certificate object we can use for subsequent tests
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        cert = (X509Certificate)cf.generateCertificate(
+                new ByteArrayInputStream(RESP_CERT_1.getBytes()));
+
+        System.out.println("============ Tests ============");
+        int testNo = 0;
+        int numberFailed = 0;
+        Map.Entry<Boolean, String> result;
+        for (TestCase test : testList) {
+            System.out.println("Test " + ++testNo + ": " + test.getName());
+            result = test.runTest();
+            System.out.print("Result: " + (result.getKey() ? "PASS" : "FAIL"));
+            System.out.println(" " +
+                    (result.getValue() != null ? result.getValue() : ""));
+            System.out.println("-------------------------------------------");
+            if (!result.getKey()) {
+                numberFailed++;
+            }
+        }
+        System.out.println("End Results: " + (testList.size() - numberFailed) +
+                " Passed" + ", " + numberFailed + " Failed.");
+        if (numberFailed > 0) {
+            throw new RuntimeException(
+                    "One or more tests failed, see test output for details");
+        }
+    }
+
+    private static void dumpHexBytes(byte[] data) {
+        if (data != null) {
+            for (int i = 0; i < data.length; i++) {
+                if (i % 16 == 0 && i != 0) {
+                    System.out.print("\n");
+                }
+                System.out.print(String.format("%02X ", data[i]));
+            }
+            System.out.print("\n");
+        }
+    }
+
+    public interface TestCase {
+        String getName();
+        Map.Entry<Boolean, String> runTest();
+    }
+
+    public static final TestCase pos_CtorByName = new TestCase() {
+        @Override
+        public String getName() {
+            return "CTOR Test (by-name)";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                respByName = new ResponderId(cert.getSubjectX500Principal());
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase pos_CtorByKeyId = new TestCase() {
+        @Override
+        public String getName() {
+            return "CTOR Test (by-keyID)";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                respByKeyId = new ResponderId(cert.getPublicKey());
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase pos_CtorByEncoding = new TestCase() {
+        @Override
+        public String getName() {
+            return "CTOR Test (encoded bytes)";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                ResponderId ridByNameBytes = new ResponderId(EXP_NAME_ID_BYTES);
+                ResponderId ridByKeyIdBytes = new ResponderId(EXP_KEY_ID_BYTES);
+
+                if (!ridByNameBytes.equals(respByName)) {
+                    throw new RuntimeException(
+                            "Equals failed: respNameFromBytes vs. respByName");
+                } else if (!ridByKeyIdBytes.equals(respByKeyId)) {
+                    throw new RuntimeException(
+                            "Equals failed: respKeyFromBytes vs. respByKeyId");
+                }
+                pass = Boolean.TRUE;
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase neg_CtorByEncoding = new TestCase() {
+        @Override
+        public String getName() {
+            return "CTOR Test (by encoding, unknown explicit tag)";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            try {
+                ResponderId ridByKeyIdBytes =
+                        new ResponderId(INV_EXPLICIT_TAG_KEY_ID);
+                throw new RuntimeException("Expected IOException not thrown");
+            } catch (IOException ioe) {
+                // Make sure it's the IOException we're looking for
+                if (ioe.getMessage().contains("Invalid ResponderId content")) {
+                    pass = Boolean.TRUE;
+                } else {
+                    ioe.printStackTrace(System.out);
+                    message = ioe.getClass().getName();
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+
+    public static final TestCase pos_Equality = new TestCase() {
+        @Override
+        public String getName() {
+            return "Simple Equality Test";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+
+            try {
+                // byName ResponderId equality test
+                ResponderId compName =
+                    new ResponderId(new X500Principal(RESP_CERT_1_SUBJ));
+                if (!respByName.equals(compName)) {
+                    message = "ResponderId mismatch in byName comparison";
+                } else if (respByKeyId.equals(compName)) {
+                    message = "Invalid ResponderId match in byKeyId comparison";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase pos_GetEncoded = new TestCase() {
+        @Override
+        public String getName() {
+            return "Get Encoded Value";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+
+            try {
+                // Pull out byName and byKey encodings, they should match
+                // the expected values
+                if (!Arrays.equals(respByName.getEncoded(), EXP_NAME_ID_BYTES)) {
+                    message = "ResponderId byName encoding did not " +
+                            "match expected value";
+                } else if (!Arrays.equals(respByKeyId.getEncoded(), EXP_KEY_ID_BYTES)) {
+                    message = "ResponderId byKeyId encoding did not " +
+                            "match expected value";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase pos_GetRespName = new TestCase() {
+        @Override
+        public String getName() {
+            return "Get Underlying Responder Name";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+
+            try {
+                // Test methods for pulling out the underlying
+                // X500Principal object
+                X500Principal testPrincipal =
+                        new X500Principal(RESP_CERT_1_SUBJ);
+                if (!respByName.getResponderName().equals(testPrincipal)) {
+                    message = "ResponderId Name did not match expected value";
+                } else if (respByKeyId.getResponderName() != null) {
+                    message = "Non-null responder name returned from " +
+                            "ResponderId constructed byKey";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    public static final TestCase pos_GetRespKeyId = new TestCase() {
+        @Override
+        public String getName() {
+            return "Get Underlying Responder Key ID";
+        }
+
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+
+            try {
+                // Test methods for pulling out the underlying
+                // KeyIdentifier object.  Note: There is a minute chance that
+                // an RSA public key, once hashed into a key ID might collide
+                // with the one extracted from the certificate used to create
+                // respByKeyId.  This is so unlikely to happen it is considered
+                // virtually impossible.
+                KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+                kpg.initialize(2048);
+                KeyPair rsaKey = kpg.generateKeyPair();
+                KeyIdentifier testKeyId = new KeyIdentifier(rsaKey.getPublic());
+
+                if (respByKeyId.getKeyIdentifier().equals(testKeyId)) {
+                    message = "Unexpected match in ResponderId Key ID";
+                } else if (respByName.getKeyIdentifier() != null) {
+                    message = "Non-null key ID returned from " +
+                            "ResponderId constructed byName";
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/AppInputStream/ReadBlocksClose.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2003, 2011, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4814140
+ * @summary AppInputStream: read can block a close
+ * @run main/othervm -Djdk.tls.acknowledgeCloseNotify=true ReadBlocksClose
+ * @author Brad Wetmore
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class ReadBlocksClose {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        try {
+            sslIS.read();
+        } catch (IOException e) {
+            // this is ok, we expect this to time out anyway if the bug
+            // is not fixed.  This is just to make sure that we
+            // don't inadvertantly fail.
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        final InputStream sslIS = sslSocket.getInputStream();
+        final OutputStream sslOS = sslSocket.getOutputStream();
+
+        new Thread(new Runnable() {
+            public void run() {
+                try {
+                    System.out.println("Closing Thread started");
+                    Thread.sleep(3000);
+                    System.out.println("Closing Thread closing");
+                    sslOS.close();
+                    System.out.println("Closing Thread closed");
+                } catch (Exception e) {
+                    RuntimeException rte =
+                        new RuntimeException("Check this out");
+                    rte.initCause(e);
+                    throw rte;
+                }
+            }
+        }).start();
+
+        try {
+            /*
+             * This should timeout and fail the test
+             */
+            System.out.println("Client starting read");
+            sslIS.read();
+        } catch (IOException e) {
+            // this is ok, we expect this to time out anyway if the bug
+            // is not fixed.  This is just to make sure that we
+            // don't inadvertantly fail.
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ReadBlocksClose();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ReadBlocksClose() throws Exception {
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            // swallow for now.  Show later
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+        String whichRemote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+            whichRemote = "server";
+        } else {
+            remote = clientException;
+            local = serverException;
+            whichRemote = "client";
+        }
+
+        /*
+         * If both failed, return the curthread's exception, but also
+         * print the remote side Exception
+         */
+        if ((local != null) && (remote != null)) {
+            System.out.println(whichRemote + " also threw:");
+            remote.printStackTrace();
+            System.out.println();
+            throw local;
+        }
+
+        if (remote != null) {
+            throw remote;
+        }
+
+        if (local != null) {
+            throw local;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/AppInputStream/ReadHandshake.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 2001, 2011, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4514971
+ * @summary Verify applications do not read handshake data after failure
+ * @run main/othervm ReadHandshake
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.security.Security;
+
+public class ReadHandshake {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    // Note: we use anonymous ciphersuites only, no keys/ trusted certs needed
+
+    private final static String[] CLIENT_SUITES = new String[] {
+        "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+    };
+
+    private final static String[] SERVER_SUITES = new String[] {
+        "SSL_DH_anon_WITH_RC4_128_MD5",
+    };
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLSocket sslSocket = null;
+        SSLServerSocket sslServerSocket = null;
+        try {
+            SSLServerSocketFactory sslssf =
+                (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+            sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(serverPort);
+            serverPort = sslServerSocket.getLocalPort();
+
+            sslServerSocket.setEnabledCipherSuites(SERVER_SUITES);
+
+            /*
+             * Signal Client, we're ready for his connect.
+             */
+            serverReady = true;
+
+            System.out.println("Server waiting for connection");
+
+            sslSocket = (SSLSocket) sslServerSocket.accept();
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            System.out.println("Server starting handshake...");
+
+
+            try {
+                sslIS.read();
+                throw new Exception("No handshake exception on server side");
+            } catch (IOException e) {
+                System.out.println("Handshake failed on server side, OK");
+            }
+
+            for (int i = 0; i < 3; i++) {
+                try {
+                    int ch;
+                    if ((ch = sslIS.read()) != -1) {
+                        throw new Exception("Read succeeded server side: "
+                            + ch);
+                    }
+                } catch (IOException e) {
+                    System.out.println("Exception for read() on server, OK");
+                }
+            }
+
+        } finally {
+            closeSocket(sslSocket);
+            closeSocket(sslServerSocket);
+        }
+    }
+
+    private static void closeSocket(Socket s) {
+        try {
+            if (s != null) {
+                s.close();
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+    }
+
+    private static void closeSocket(ServerSocket s) {
+        try {
+            if (s != null) {
+                s.close();
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(80);
+        }
+
+        SSLSocket sslSocket = null;
+        try {
+
+            SSLSocketFactory sslsf =
+                (SSLSocketFactory) SSLSocketFactory.getDefault();
+            sslSocket = (SSLSocket)
+                sslsf.createSocket("localhost", serverPort);
+            sslSocket.setEnabledCipherSuites(CLIENT_SUITES);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            System.out.println("Client starting handshake...");
+
+            try {
+                sslIS.read();
+                throw new Exception("No handshake exception on client side");
+            } catch (IOException e) {
+                System.out.println("Handshake failed on client side, OK");
+            }
+
+            for (int i = 0; i < 3; i++) {
+                try {
+                    int ch;
+                    if ((ch = sslIS.read()) != -1) {
+                        throw new Exception("Read succeeded on client side: "
+                            + ch);
+                    }
+                } catch (IOException e) {
+                    System.out.println("Exception for read() on client, OK");
+                }
+            }
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ReadHandshake();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ReadHandshake() throws Exception {
+        startServer(true);
+        startClient(true);
+
+        serverThread.join();
+        clientThread.join();
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            if (clientException != null) {
+                System.out.println("Client exception:");
+                clientException.printStackTrace(System.out);
+            }
+            throw serverException;
+        }
+        if (clientException != null) {
+            throw clientException;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/AppOutputStream/NoExceptionOnClose.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test 1.3 01/03/08
+ * @bug 4378397
+ * @summary  JSSE socket output stream doesn't throw after socket is closed
+ * @run main/othervm NoExceptionOnClose
+ * @author Jaya Hangal
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class NoExceptionOnClose {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    boolean useSSL = true;
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        ServerSocket  serverSocket;
+        if (useSSL) {
+            SSLServerSocketFactory sslssf =
+                (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+            serverSocket = (SSLServerSocket) sslssf.
+                        createServerSocket(serverPort);
+        } else {
+           serverSocket = new ServerSocket(serverPort);
+        }
+        serverPort = serverSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        Socket socket =  serverSocket.accept();
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        int read = sslIS.read();
+        System.out.println("Server read: " + read);
+        sslOS.write(85);
+        sslOS.flush();
+        socket.close();
+        socket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+        Socket socket;
+        if (useSSL) {
+            SSLSocketFactory sslsf =
+                        (SSLSocketFactory) SSLSocketFactory.getDefault();
+            socket = (SSLSocket)
+                sslsf.createSocket("localhost", serverPort);
+        } else
+                socket = new Socket("localhost", serverPort);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(80);
+        sslOS.flush();
+        int read = sslIS.read();
+        System.out.println("client read: " + read);
+        socket.close();
+        /*
+         * The socket closed exception must be thrown here
+         */
+        boolean isSocketClosedThrown = false;
+        try {
+            sslOS.write(22);
+            sslOS.flush();
+        } catch (SSLException | SocketException socketClosed) {
+                System.out.println("Received \"" + socketClosed.getMessage()
+                        + "\" exception as expected");
+                isSocketClosedThrown = true;
+        }
+        if (!isSocketClosedThrown) {
+                throw new Exception("No Exception thrown on write() after"
+                                + " close()");
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new NoExceptionOnClose();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    NoExceptionOnClose() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null)
+            throw serverException;
+        if (clientException != null)
+            throw clientException;
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/CertPathRestrictions/JSSEServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2017, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+
+/*
+ * A SSL socket server.
+ */
+public class JSSEServer {
+
+    private SSLServerSocket server = null;
+
+    public JSSEServer(SSLContext context, String constraint,
+            boolean needClientAuth) throws Exception {
+        TLSRestrictions.setConstraint("Server", constraint);
+
+        SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
+        server = (SSLServerSocket) serverFactory.createServerSocket(0);
+        server.setSoTimeout(TLSRestrictions.TIMEOUT);
+        server.setNeedClientAuth(needClientAuth); // for dual authentication
+        System.out.println("Server: port=" + getPort());
+    }
+
+    public Exception start() {
+        System.out.println("Server: started");
+        Exception exception = null;
+        try (SSLSocket socket = (SSLSocket) server.accept()) {
+            System.out.println("Server: accepted connection");
+            socket.setSoTimeout(TLSRestrictions.TIMEOUT);
+            InputStream sslIS = socket.getInputStream();
+            OutputStream sslOS = socket.getOutputStream();
+            sslIS.read();
+            sslOS.write('S');
+            sslOS.flush();
+            System.out.println("Server: finished");
+        } catch (Exception e) {
+            exception = e;
+            e.printStackTrace(System.out);
+            System.out.println("Server: failed");
+        }
+
+        return exception;
+    }
+
+    public int getPort() {
+        return server.getLocalPort();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/CertPathRestrictions/TLSRestrictions.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2017, 2018, 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.
+ *
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.SocketTimeoutException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.KeyFactory;
+import java.security.KeyStore;
+import java.security.PrivateKey;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManagerFactory;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * @test
+ * @bug 8165367
+ * @summary Verify the restrictions for certificate path on JSSE with custom trust store.
+ * @library /test/lib
+ * @build jdk.test.lib.Utils
+ *        jdk.test.lib.Asserts
+ *        jdk.test.lib.JDKToolFinder
+ *        jdk.test.lib.JDKToolLauncher
+ *        jdk.test.lib.Platform
+ *        jdk.test.lib.process.*
+ * @compile JSSEClient.java
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions DEFAULT
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C1
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S1
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C2
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S2
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C3
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S3
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C4
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S4
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C5
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S5
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C6
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S6
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C7
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S7
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C8
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S8
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions C9
+ * @run main/othervm -Djava.security.debug=certpath TLSRestrictions S9
+ */
+public class TLSRestrictions {
+
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+    private static final char[] PASSWORD = "".toCharArray();
+    private static final String CERT_DIR = System.getProperty("cert.dir",
+            System.getProperty("test.src") + "/certs");
+
+    static final String PROP = "jdk.certpath.disabledAlgorithms";
+    static final String NOSHA1 = "MD2, MD5";
+    private static final String TLSSERVER = "SHA1 usage TLSServer";
+    private static final String TLSCLIENT = "SHA1 usage TLSClient";
+    static final String JDKCATLSSERVER = "SHA1 jdkCA & usage TLSServer";
+    static final String JDKCATLSCLIENT = "SHA1 jdkCA & usage TLSClient";
+
+    // This is a space holder in command arguments, and stands for none certificate.
+    static final String NONE_CERT = "NONE_CERT";
+
+    static final String DELIMITER = ",";
+    static final int TIMEOUT = 30000;
+
+    // It checks if java.security contains constraint "SHA1 jdkCA & usage TLSServer"
+    // for jdk.certpath.disabledAlgorithms by default.
+    private static void checkDefaultConstraint() {
+        System.out.println(
+                "Case: Checks the default value of jdk.certpath.disabledAlgorithms");
+        if (!Security.getProperty(PROP).contains(JDKCATLSSERVER)) {
+            throw new RuntimeException(String.format(
+                    "%s doesn't contain constraint \"%s\", the real value is \"%s\".",
+                    PROP, JDKCATLSSERVER, Security.getProperty(PROP)));
+        }
+    }
+
+    /*
+     * This method creates trust store and key store with specified certificates
+     * respectively. And then it creates SSL context with the stores.
+     * If trustNames contains NONE_CERT only, it does not create a custom trust
+     * store, but the default one in JDK.
+     *
+     * @param trustNames Trust anchors, which are used to create custom trust store.
+     *                   If null, no custom trust store is created and the default
+     *                   trust store in JDK is used.
+     * @param certNames Certificate chain, which is used to create key store.
+     *                  It cannot be null.
+     */
+    static SSLContext createSSLContext(String[] trustNames,
+            String[] certNames) throws Exception {
+        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
+
+        TrustManagerFactory tmf = null;
+        if (trustNames != null && trustNames.length > 0
+                && !trustNames[0].equals(NONE_CERT)) {
+            KeyStore trustStore = KeyStore.getInstance("JKS");
+            trustStore.load(null, null);
+            for (int i = 0; i < trustNames.length; i++) {
+                try (InputStream is = new ByteArrayInputStream(
+                        loadCert(trustNames[i]).getBytes())) {
+                    Certificate trustCert = certFactory.generateCertificate(is);
+                    trustStore.setCertificateEntry("trustCert-" + i, trustCert);
+                }
+            }
+
+            tmf = TrustManagerFactory.getInstance("PKIX");
+            tmf.init(trustStore);
+        }
+
+        Certificate[] certChain = new Certificate[certNames.length];
+        for (int i = 0; i < certNames.length; i++) {
+            try (InputStream is = new ByteArrayInputStream(
+                    loadCert(certNames[i]).getBytes())) {
+                Certificate cert = certFactory.generateCertificate(is);
+                certChain[i] = cert;
+            }
+        }
+
+        PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
+                Base64.getMimeDecoder().decode(loadPrivKey(certNames[0])));
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
+
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        keyStore.load(null, null);
+        keyStore.setKeyEntry("keyCert", privKey, PASSWORD, certChain);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(keyStore, PASSWORD);
+
+        SSLContext context = SSLContext.getInstance("TLS");
+        context.init(kmf.getKeyManagers(),
+                tmf == null ? null : tmf.getTrustManagers(), null);
+        return context;
+    }
+
+    /*
+     * This method sets jdk.certpath.disabledAlgorithms, and then retrieves
+     * and prints its value.
+     */
+    static void setConstraint(String side, String constraint) {
+        System.out.printf("%s: Old %s=%s%n", side, PROP,
+                Security.getProperty(PROP));
+        Security.setProperty(PROP, constraint);
+        System.out.printf("%s: New %s=%s%n", side, PROP,
+                Security.getProperty(PROP));
+    }
+
+    /*
+     * This method is used to run a variety of cases.
+     * It launches a server, and then takes a client to connect the server.
+     * Both of server and client use the same certificates.
+     *
+     * @param trustNames Trust anchors, which are used to create custom trust store.
+     *                   If null, the default trust store in JDK is used.
+     * @param certNames Certificate chain, which is used to create key store.
+     *                  It cannot be null. The first certificate is regarded as
+     *                  the end entity.
+     * @param serverConstraint jdk.certpath.disabledAlgorithms value on server side.
+     * @param clientConstraint jdk.certpath.disabledAlgorithms value on client side.
+     * @param needClientAuth If true, server side acquires client authentication;
+     *                       otherwise, false.
+     * @param pass If true, the connection should be blocked; otherwise, false.
+     */
+    static void testConstraint(String[] trustNames, String[] certNames,
+            String serverConstraint, String clientConstraint,
+            boolean needClientAuth, boolean pass) throws Exception {
+        String trustNameStr = trustNames == null ? ""
+                : String.join(DELIMITER, trustNames);
+        String certNameStr = certNames == null ? ""
+                : String.join(DELIMITER, certNames);
+
+        System.out.printf("Case:%n"
+                + "  trustNames=%s; certNames=%s%n"
+                + "  serverConstraint=%s; clientConstraint=%s%n"
+                + "  needClientAuth=%s%n"
+                + "  pass=%s%n%n",
+                trustNameStr, certNameStr,
+                serverConstraint, clientConstraint,
+                needClientAuth,
+                pass);
+
+        ExecutorService executor = Executors.newFixedThreadPool(1);
+        try {
+            JSSEServer server = new JSSEServer(
+                    createSSLContext(trustNames, certNames),
+                    serverConstraint,
+                    needClientAuth);
+            int port = server.getPort();
+            Future<Exception> serverFuture = executor.submit(() -> server.start());
+
+            // Run client on another JVM so that its properties cannot be in conflict
+            // with server's.
+            OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJvm(
+                    "-Dcert.dir=" + CERT_DIR,
+                    "-Djava.security.debug=certpath",
+                    "-classpath",
+                    TEST_CLASSES,
+                    "JSSEClient",
+                    port + "",
+                    trustNameStr,
+                    certNameStr,
+                    clientConstraint);
+            int clientExitValue = outputAnalyzer.getExitValue();
+            String clientOut = outputAnalyzer.getOutput();
+            System.out.println("---------- Client output start ----------");
+            System.out.println(clientOut);
+            System.out.println("---------- Client output end ----------");
+
+            Exception serverException = serverFuture.get(TIMEOUT, TimeUnit.MILLISECONDS);
+            if (serverException instanceof SocketTimeoutException
+                    || clientOut.contains("SocketTimeoutException")) {
+                System.out.println("The communication gets timeout and skips the test.");
+                return;
+            }
+
+            if (pass) {
+                if (serverException != null || clientExitValue != 0) {
+                    throw new RuntimeException(
+                            "Unexpected failure. Operation was blocked.");
+                }
+            } else {
+                if (serverException == null && clientExitValue == 0) {
+                    throw new RuntimeException(
+                            "Unexpected pass. Operation was allowed.");
+                }
+
+                // The test may encounter non-SSL issues, like network problem.
+                if (!(serverException instanceof SSLHandshakeException
+                        || clientOut.contains("SSLHandshakeException"))) {
+                    throw new RuntimeException("Failure with unexpected exception.");
+                }
+            }
+        } finally {
+            executor.shutdown();
+        }
+    }
+
+    /*
+     * This method is used to run a variety of cases, which don't require client
+     * authentication by default.
+     */
+    static void testConstraint(String[] trustNames, String[] certNames,
+            String serverConstraint, String clientConstraint, boolean pass)
+            throws Exception {
+        testConstraint(trustNames, certNames, serverConstraint, clientConstraint,
+                false, pass);
+    }
+
+    public static void main(String[] args) throws Exception {
+        switch (args[0]) {
+        // Case DEFAULT only checks one of default settings for
+        // jdk.certpath.disabledAlgorithms in JDK/conf/security/java.security.
+        case "DEFAULT":
+            checkDefaultConstraint();
+            break;
+
+        // Cases C1 and S1 use SHA256 root CA in trust store,
+        // and use SHA256 end entity in key store.
+        // C1 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S1 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should not be blocked.
+        case "C1":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] { "INTER_CA_SHA256-ROOT_CA_SHA256" },
+                    NOSHA1,
+                    TLSSERVER,
+                    true);
+            break;
+        case "S1":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] { "INTER_CA_SHA256-ROOT_CA_SHA256" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    true);
+            break;
+
+        // Cases C2 and S2 use SHA256 root CA in trust store,
+        // and use SHA1 end entity in key store.
+        // C2 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S2 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should be blocked.
+        case "C2":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] { "INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    NOSHA1,
+                    TLSSERVER,
+                    false);
+            break;
+        case "S2":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] { "INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    false);
+            break;
+
+        // Cases C3 and S3 use SHA1 root CA in trust store,
+        // and use SHA1 end entity in key store.
+        // C3 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S3 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should be blocked.
+        case "C3":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] { "INTER_CA_SHA1-ROOT_CA_SHA1" },
+                    NOSHA1,
+                    TLSSERVER,
+                    false);
+            break;
+        case "S3":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] { "INTER_CA_SHA1-ROOT_CA_SHA1" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    false);
+            break;
+
+        // Cases C4 and S4 use SHA1 root CA as trust store,
+        // and use SHA256 end entity in key store.
+        // C4 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S4 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should not be blocked.
+        case "C4":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] { "INTER_CA_SHA256-ROOT_CA_SHA1" },
+                    NOSHA1,
+                    TLSSERVER,
+                    true);
+            break;
+        case "S4":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] { "INTER_CA_SHA256-ROOT_CA_SHA1" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    true);
+            break;
+
+        // Cases C5 and S5 use SHA1 root CA in trust store,
+        // and use SHA256 intermediate CA and SHA256 end entity in key store.
+        // C5 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S5 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should not be blocked.
+        case "C5":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA256-ROOT_CA_SHA1",
+                            "INTER_CA_SHA256-ROOT_CA_SHA1" },
+                    NOSHA1,
+                    TLSSERVER,
+                    true);
+            break;
+        case "S5":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA256-ROOT_CA_SHA1",
+                            "INTER_CA_SHA256-ROOT_CA_SHA1" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    true);
+            break;
+
+        // Cases C6 and S6 use SHA1 root CA as trust store,
+        // and use SHA1 intermediate CA and SHA256 end entity in key store.
+        // C6 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S6 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should be blocked.
+        case "C6":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA1-ROOT_CA_SHA1",
+                            "INTER_CA_SHA1-ROOT_CA_SHA1" },
+                    NOSHA1,
+                    TLSSERVER,
+                    false);
+            break;
+        case "S6":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA1" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA1-ROOT_CA_SHA1",
+                            "INTER_CA_SHA1-ROOT_CA_SHA1" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    false);
+            break;
+
+        // Cases C7 and S7 use SHA256 root CA in trust store,
+        // and use SHA256 intermediate CA and SHA1 end entity in key store.
+        // C7 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S7 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should be blocked.
+        case "C7":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] {
+                            "END_ENTITY_SHA1-INTER_CA_SHA256-ROOT_CA_SHA256",
+                            "INTER_CA_SHA256-ROOT_CA_SHA256" },
+                    NOSHA1,
+                    TLSSERVER,
+                    false);
+            break;
+        case "S7":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] {
+                            "END_ENTITY_SHA1-INTER_CA_SHA256-ROOT_CA_SHA256",
+                            "INTER_CA_SHA256-ROOT_CA_SHA256" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    false);
+            break;
+
+        // Cases C8 and S8 use SHA256 root CA in trust store,
+        // and use SHA1 intermediate CA and SHA256 end entity in key store.
+        // C8 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S8 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should be blocked.
+        case "C8":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA1-ROOT_CA_SHA256",
+                            "INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    NOSHA1,
+                    TLSSERVER,
+                    false);
+            break;
+        case "S8":
+            testConstraint(
+                    new String[] { "ROOT_CA_SHA256" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA1-ROOT_CA_SHA256",
+                            "INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    false);
+            break;
+
+        // Cases C9 and S9 use SHA256 root CA and SHA1 intermediate CA in trust store,
+        // and use SHA256 end entity in key store.
+        // C9 only sets constraint "SHA1 usage TLSServer" on client side;
+        // S9 only sets constraint "SHA1 usage TLSClient" on server side with client auth.
+        // The connection of the both cases should not be blocked.
+        case "C9":
+            testConstraint(
+                    new String[] {
+                            "ROOT_CA_SHA256",
+                            "INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    NOSHA1,
+                    TLSSERVER,
+                    true);
+            break;
+        case "S9":
+            testConstraint(
+                    new String[] {
+                            "ROOT_CA_SHA256",
+                            "INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    new String[] {
+                            "END_ENTITY_SHA256-INTER_CA_SHA1-ROOT_CA_SHA256" },
+                    TLSCLIENT,
+                    NOSHA1,
+                    true,
+                    true);
+            break;
+        }
+        System.out.println("Case passed");
+        System.out.println("========================================");
+    }
+
+    private static String loadCert(String certName) {
+        try {
+            Path certFilePath = Paths.get(CERT_DIR, certName + ".cer");
+            return String.join("\n",
+                    Files.lines(certFilePath).filter((String line) -> {
+                        return !line.startsWith("Certificate")
+                                && !line.startsWith(" ");
+                    }).collect(Collectors.toList()));
+        } catch (IOException e) {
+            throw new RuntimeException("Load certificate failed", e);
+        }
+    }
+
+    private static String loadPrivKey(String certName) {
+        Path priveKeyFilePath = Paths.get(CERT_DIR, certName + "-PRIV.key");
+        try {
+            return new String(Files.readAllBytes(priveKeyFilePath));
+        } catch (IOException e) {
+            throw new RuntimeException("Load private key failed", e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/CipherSuite/SSL_NULL.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2003, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 4854838
+ * @summary Verify that SSL_NULL_WITH_NULL_NULL is returned as ciphersuite
+ *      if the handshake fails
+ * @author Andreas Sterbenz
+ */
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+import javax.net.ssl.*;
+
+public class SSL_NULL {
+    private static volatile Boolean result;
+
+    public static void main(String[] args) throws Exception {
+        final SSLServerSocket serverSocket = (SSLServerSocket)
+            SSLServerSocketFactory.getDefault().createServerSocket(0);
+        serverSocket.setEnabledCipherSuites(
+            serverSocket.getSupportedCipherSuites());
+        new Thread() {
+            public void run() {
+                try {
+                    SSLSocket socket = (SSLSocket) serverSocket.accept();
+                    String suite = socket.getSession().getCipherSuite();
+                    if (!"SSL_NULL_WITH_NULL_NULL".equals(suite)) {
+                        System.err.println(
+                            "Wrong suite for failed handshake: " +
+                            "got " + suite +
+                            ", expected SSL_NULL_WITH_NULL_NULL");
+                    } else {
+                        result = Boolean.TRUE;
+                        return;
+                    }
+                } catch (IOException e) {
+                    System.err.println("Unexpected exception");
+                    e.printStackTrace();
+                } finally {
+                    if (result == null) {
+                        result = Boolean.FALSE;
+                    }
+                }
+            }
+        }.start();
+
+        SSLSocket socket = (SSLSocket)
+            SSLSocketFactory.getDefault().createSocket(
+                "localhost", serverSocket.getLocalPort());
+        socket.setEnabledCipherSuites(
+            new String[] { "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" });
+        try {
+            OutputStream out = socket.getOutputStream();
+            out.write(0);
+            out.flush();
+            throw new RuntimeException("No exception received");
+        } catch (SSLHandshakeException e) {
+            System.out.println("Expected handshake exception: " + e);
+        }
+
+        System.out.println("client: " + socket.getSession().getCipherSuite());
+
+        // wait for other thread to set result
+        while (result == null) {
+            Thread.sleep(50);
+        }
+        if (result.booleanValue()) {
+            System.out.println("Test passed");
+        } else {
+            throw new Exception("Test failed");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,818 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8044860
+ * @summary Vectors and fixed length fields should be verified
+ *          for allowed sizes.
+ * @modules java.base/sun.security.ssl
+ * @run main/othervm LengthCheckTest
+ * @key randomness
+ */
+
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class LengthCheckTest {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+    private static final boolean dumpBufs = true;
+
+    private final SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    private HandshakeTest handshakeTest;
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static final String pathToStores = "../../../../javax/net/ssl/etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    // Define a few basic TLS record and message types we might need
+    private static final int TLS_RECTYPE_CCS = 0x14;
+    private static final int TLS_RECTYPE_ALERT = 0x15;
+    private static final int TLS_RECTYPE_HANDSHAKE = 0x16;
+    private static final int TLS_RECTYPE_APPDATA = 0x17;
+
+    private static final int TLS_HS_HELLO_REQUEST = 0x00;
+    private static final int TLS_HS_CLIENT_HELLO = 0x01;
+    private static final int TLS_HS_SERVER_HELLO = 0x02;
+    private static final int TLS_HS_CERTIFICATE = 0x0B;
+    private static final int TLS_HS_SERVER_KEY_EXCHG = 0x0C;
+    private static final int TLS_HS_CERT_REQUEST = 0x0D;
+    private static final int TLS_HS_SERVER_HELLO_DONE = 0x0E;
+    private static final int TLS_HS_CERT_VERIFY = 0x0F;
+    private static final int TLS_HS_CLIENT_KEY_EXCHG = 0x10;
+    private static final int TLS_HS_FINISHED = 0x14;
+
+    // We're not going to define all the alert types in TLS, just
+    // the ones we think we'll need to reference by name.
+    private static final int TLS_ALERT_LVL_WARNING = 0x01;
+    private static final int TLS_ALERT_LVL_FATAL = 0x02;
+
+    private static final int TLS_ALERT_UNEXPECTED_MSG = 0x0A;
+    private static final int TLS_ALERT_HANDSHAKE_FAILURE = 0x28;
+    private static final int TLS_ALERT_INTERNAL_ERROR = 0x50;
+    private static final int TLS_ALERT_ILLEGAL_PARAMETER = 0x2F;
+
+    public interface HandshakeTest {
+        void execTest() throws Exception;
+    }
+
+    public final HandshakeTest servSendLongID = new HandshakeTest() {
+        @Override
+        public void execTest() throws Exception {
+            boolean gotException = false;
+            SSLEngineResult clientResult;   // results from client's last op
+            SSLEngineResult serverResult;   // results from server's last op
+
+            log("\n==== Test: Client receives 64-byte session ID ====");
+
+            // Send Client Hello
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+            cTOs.flip();
+            dumpByteBuffer("CLIENT-TO-SERVER", cTOs);
+
+            // Server consumes Client Hello
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            log("server unwrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            cTOs.compact();
+
+            // Server generates ServerHello/Cert/Done record
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            sTOc.flip();
+
+            // Intercept the ServerHello messages and instead send
+            // one that has a 64-byte session ID.
+            if (isTlsMessage(sTOc, TLS_RECTYPE_HANDSHAKE,
+                        TLS_HS_SERVER_HELLO)) {
+                ArrayList<ByteBuffer> recList = splitRecord(sTOc);
+
+                // Use the original ServerHello as a template to craft one
+                // with a longer-than-allowed session ID.
+                ByteBuffer servHelloBuf =
+                        createEvilServerHello(recList.get(0), 64);
+
+                recList.set(0, servHelloBuf);
+
+                // Now send each ByteBuffer (each being a complete
+                // TLS record) into the client-side unwrap.
+                // for (ByteBuffer bBuf : recList) {
+
+                Iterator<ByteBuffer> iter = recList.iterator();
+                while (!gotException && (iter.hasNext())) {
+                    ByteBuffer bBuf = iter.next();
+                    dumpByteBuffer("SERVER-TO-CLIENT", bBuf);
+                    try {
+                        clientResult = clientEngine.unwrap(bBuf, clientIn);
+                    } catch (SSLProtocolException e) {
+                        log("Received expected SSLProtocolException: " + e);
+                        gotException = true;
+                    }
+                    log("client unwrap: ", clientResult);
+                    runDelegatedTasks(clientResult, clientEngine);
+                }
+            } else {
+                dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
+                log("client unwrap: ", clientResult);
+                runDelegatedTasks(clientResult, clientEngine);
+            }
+            sTOc.compact();
+
+            // The Client should now send a TLS Alert
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+            cTOs.flip();
+            dumpByteBuffer("CLIENT-TO-SERVER", cTOs);
+
+            // At this point we can verify that both an exception
+            // was thrown and the proper action (a TLS alert) was
+            // sent back to the server.
+            if (gotException == false ||
+                    !isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
+                            TLS_ALERT_ILLEGAL_PARAMETER)) {
+                throw new SSLException(
+                    "Client failed to throw Alert:fatal:internal_error");
+            }
+        }
+    };
+
+    public final HandshakeTest clientSendLongID = new HandshakeTest() {
+        @Override
+        public void execTest() throws Exception {
+            boolean gotException = false;
+            SSLEngineResult clientResult;   // results from client's last op
+            SSLEngineResult serverResult;   // results from server's last op
+
+            log("\n==== Test: Server receives 64-byte session ID ====");
+
+            // Send Client Hello
+            ByteBuffer evilClientHello = createEvilClientHello(64);
+            dumpByteBuffer("CLIENT-TO-SERVER", evilClientHello);
+
+            // Server consumes Client Hello
+            serverResult = serverEngine.unwrap(evilClientHello, serverIn);
+            log("server unwrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            evilClientHello.compact();
+
+            // Under normal circumstances this should be a ServerHello
+            // But should throw an exception instead due to the invalid
+            // session ID.
+            try {
+                serverResult = serverEngine.wrap(serverOut, sTOc);
+                log("server wrap: ", serverResult);
+                runDelegatedTasks(serverResult, serverEngine);
+            } catch (SSLProtocolException ssle) {
+                log("Received expected SSLProtocolException: " + ssle);
+                gotException = true;
+            }
+
+            // We expect to see the server generate an alert here
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            sTOc.flip();
+            dumpByteBuffer("SERVER-TO-CLIENT", sTOc);
+
+            // At this point we can verify that both an exception
+            // was thrown and the proper action (a TLS alert) was
+            // sent back to the client.
+            if (gotException == false ||
+                    !isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
+                        TLS_ALERT_ILLEGAL_PARAMETER)) {
+                throw new SSLException(
+                    "Server failed to throw Alert:fatal:internal_error");
+            }
+        }
+    };
+
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        List<LengthCheckTest> ccsTests = new ArrayList<>();
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "ssl");
+        }
+
+        ccsTests.add(new LengthCheckTest("ServSendLongID"));
+        ccsTests.add(new LengthCheckTest("ClientSendLongID"));
+
+        for (LengthCheckTest test : ccsTests) {
+            test.runTest();
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public LengthCheckTest(String testName) throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+
+        switch (testName) {
+            case "ServSendLongID":
+                handshakeTest = servSendLongID;
+                break;
+            case "ClientSendLongID":
+                handshakeTest = clientSendLongID;
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown test name: " +
+                        testName);
+        }
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        handshakeTest.execTest();
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(false);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+
+        // In order to make a test that will be backwards compatible
+        // going back to JDK 5, force the handshake to be TLS 1.0 and
+        // use one of the older cipher suites.
+        clientEngine.setEnabledProtocols(new String[]{"TLSv1"});
+        clientEngine.setEnabledCipherSuites(
+                new String[]{"TLS_RSA_WITH_AES_128_CBC_SHA"});
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+
+    /**
+     * Split a record consisting of multiple TLS handshake messages
+     * into individual TLS records, each one in a ByteBuffer of its own.
+     *
+     * @param tlsRecord A ByteBuffer containing the tls record data.
+     *        The position of the buffer should be at the first byte
+     *        in the TLS record data.
+     *
+     * @return An ArrayList consisting of one or more ByteBuffers.  Each
+     *         ByteBuffer will contain a single TLS record with one message.
+     *         That message will be taken from the input record.  The order
+     *         of the messages in the ArrayList will be the same as they
+     *         were in the input record.
+     */
+    private ArrayList<ByteBuffer> splitRecord(ByteBuffer tlsRecord) {
+        SSLSession session = clientEngine.getSession();
+        int netBufferMax = session.getPacketBufferSize();
+        ArrayList<ByteBuffer> recordList = new ArrayList<>();
+
+        if (tlsRecord.hasRemaining()) {
+            int type = Byte.toUnsignedInt(tlsRecord.get());
+            byte ver_major = tlsRecord.get();
+            byte ver_minor = tlsRecord.get();
+            int recLen = Short.toUnsignedInt(tlsRecord.getShort());
+            byte[] newMsgData = null;
+            while (tlsRecord.hasRemaining()) {
+                ByteBuffer newRecord = ByteBuffer.allocateDirect(netBufferMax);
+                switch (type) {
+                    case TLS_RECTYPE_CCS:
+                    case TLS_RECTYPE_ALERT:
+                    case TLS_RECTYPE_APPDATA:
+                        // None of our tests have multiple non-handshake
+                        // messages coalesced into a single record.
+                        break;
+                    case TLS_RECTYPE_HANDSHAKE:
+                        newMsgData = getHandshakeMessage(tlsRecord);
+                        break;
+                }
+
+                // Put a new TLS record on the destination ByteBuffer
+                newRecord.put((byte)type);
+                newRecord.put(ver_major);
+                newRecord.put(ver_minor);
+                newRecord.putShort((short)newMsgData.length);
+
+                // Now add the message content itself and attach to the
+                // returned ArrayList
+                newRecord.put(newMsgData);
+                newRecord.flip();
+                recordList.add(newRecord);
+            }
+        }
+
+        return recordList;
+    }
+
+    private static ByteBuffer createEvilClientHello(int sessIdLen) {
+        ByteBuffer newRecord = ByteBuffer.allocateDirect(4096);
+
+        // Lengths will initially be place holders until we determine the
+        // finished length of the ByteBuffer.  Then we'll go back and scribble
+        // in the correct lengths.
+
+        newRecord.put((byte)TLS_RECTYPE_HANDSHAKE);     // Record type
+        newRecord.putShort((short)0x0301);              // Protocol (TLS 1.0)
+        newRecord.putShort((short)0);                   // Length place holder
+
+        newRecord.putInt(TLS_HS_CLIENT_HELLO << 24);    // HS type and length
+        newRecord.putShort((short)0x0301);
+        newRecord.putInt((int)(System.currentTimeMillis() / 1000));
+        SecureRandom sr = new SecureRandom();
+        byte[] randBuf = new byte[28];
+        sr.nextBytes(randBuf);
+        newRecord.put(randBuf);                         // Client Random
+        newRecord.put((byte)sessIdLen);                 // Session ID length
+        if (sessIdLen > 0) {
+            byte[] sessId = new byte[sessIdLen];
+            sr.nextBytes(sessId);
+            newRecord.put(sessId);                      // Session ID
+        }
+        newRecord.putShort((short)2);                   // 2 bytes of ciphers
+        newRecord.putShort((short)0x002F);              // TLS_RSA_AES_CBC_SHA
+        newRecord.putShort((short)0x0100);              // only null compression
+        newRecord.putShort((short)5);                   // 5 bytes of extensions
+        newRecord.putShort((short)0xFF01);              // Renegotiation info
+        newRecord.putShort((short)1);
+        newRecord.put((byte)0);                         // No reneg info exts
+
+        // Go back and fill in the correct length values for the record
+        // and handshake message headers.
+        int recordLength = newRecord.position();
+        newRecord.putShort(3, (short)(recordLength - 5));
+        int newTypeAndLen = (newRecord.getInt(5) & 0xFF000000) |
+                ((recordLength - 9) & 0x00FFFFFF);
+        newRecord.putInt(5, newTypeAndLen);
+
+        newRecord.flip();
+        return newRecord;
+    }
+
+    private static ByteBuffer createEvilServerHello(ByteBuffer origHello,
+            int newSessIdLen) {
+        if (newSessIdLen < 0 || newSessIdLen > Byte.MAX_VALUE) {
+            throw new RuntimeException("Length must be 0 <= X <= 127");
+        }
+
+        ByteBuffer newRecord = ByteBuffer.allocateDirect(4096);
+        // Copy the bytes from the old hello to the new up to the session ID
+        // field.  We will go back later and fill in a new length field in
+        // the record header.  This includes the record header (5 bytes), the
+        // Handshake message header (4 bytes), protocol version (2 bytes),
+        // and the random (32 bytes).
+        ByteBuffer scratchBuffer = origHello.slice();
+        scratchBuffer.limit(43);
+        newRecord.put(scratchBuffer);
+
+        // Advance the position in the originial hello buffer past the
+        // session ID.
+        origHello.position(43);
+        int origIDLen = Byte.toUnsignedInt(origHello.get());
+        if (origIDLen > 0) {
+            // Skip over the session ID
+            origHello.position(origHello.position() + origIDLen);
+        }
+
+        // Now add our own sessionID to the new record
+        SecureRandom sr = new SecureRandom();
+        byte[] sessId = new byte[newSessIdLen];
+        sr.nextBytes(sessId);
+        newRecord.put((byte)newSessIdLen);
+        newRecord.put(sessId);
+
+        // Create another slice in the original buffer, based on the position
+        // past the session ID.  Copy the remaining bytes into the new
+        // hello buffer.  Then go back and fix up the length
+        newRecord.put(origHello.slice());
+
+        // Go back and fill in the correct length values for the record
+        // and handshake message headers.
+        int recordLength = newRecord.position();
+        newRecord.putShort(3, (short)(recordLength - 5));
+        int newTypeAndLen = (newRecord.getInt(5) & 0xFF000000) |
+                ((recordLength - 9) & 0x00FFFFFF);
+        newRecord.putInt(5, newTypeAndLen);
+
+        newRecord.flip();
+        return newRecord;
+    }
+
+    /**
+     * Look at an incoming TLS record and see if it is the desired
+     * record type, and where appropriate the correct subtype.
+     *
+     * @param srcRecord The input TLS record to be evaluated.  This
+     *        method will only look at the leading message if multiple
+     *        TLS handshake messages are coalesced into a single record.
+     * @param reqRecType The requested TLS record type
+     * @param recParams Zero or more integer sub type fields.  For CCS
+     *        and ApplicationData, no params are used.  For handshake records,
+     *        one value corresponding to the HandshakeType is required.
+     *        For Alerts, two values corresponding to AlertLevel and
+     *        AlertDescription are necessary.
+     *
+     * @return true if the proper handshake message is the first one
+     *         in the input record, false otherwise.
+     */
+    private boolean isTlsMessage(ByteBuffer srcRecord, int reqRecType,
+            int... recParams) {
+        boolean foundMsg = false;
+
+        if (srcRecord.hasRemaining()) {
+            srcRecord.mark();
+
+            // Grab the fields from the TLS Record
+            int recordType = Byte.toUnsignedInt(srcRecord.get());
+            byte ver_major = srcRecord.get();
+            byte ver_minor = srcRecord.get();
+            int recLen = Short.toUnsignedInt(srcRecord.getShort());
+
+            if (recordType == reqRecType) {
+                // For any zero-length recParams, making sure the requested
+                // type is sufficient.
+                if (recParams.length == 0) {
+                    foundMsg = true;
+                } else {
+                    switch (recordType) {
+                        case TLS_RECTYPE_CCS:
+                        case TLS_RECTYPE_APPDATA:
+                            // We really shouldn't find ourselves here, but
+                            // if someone asked for these types and had more
+                            // recParams we can ignore them.
+                            foundMsg = true;
+                            break;
+                        case TLS_RECTYPE_ALERT:
+                            // Needs two params, AlertLevel and AlertDescription
+                            if (recParams.length != 2) {
+                                throw new RuntimeException(
+                                    "Test for Alert requires level and desc.");
+                            } else {
+                                int level = Byte.toUnsignedInt(srcRecord.get());
+                                int desc = Byte.toUnsignedInt(srcRecord.get());
+                                if (level == recParams[0] &&
+                                        desc == recParams[1]) {
+                                    foundMsg = true;
+                                }
+                            }
+                            break;
+                        case TLS_RECTYPE_HANDSHAKE:
+                            // Needs one parameter, HandshakeType
+                            if (recParams.length != 1) {
+                                throw new RuntimeException(
+                                    "Test for Handshake requires only HS type");
+                            } else {
+                                // Go into the first handhshake message in the
+                                // record and grab the handshake message header.
+                                // All we need to do is parse out the leading
+                                // byte.
+                                int msgHdr = srcRecord.getInt();
+                                int msgType = (msgHdr >> 24) & 0x000000FF;
+                                if (msgType == recParams[0]) {
+                                foundMsg = true;
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+
+            srcRecord.reset();
+        }
+
+        return foundMsg;
+    }
+
+    private byte[] getHandshakeMessage(ByteBuffer srcRecord) {
+        // At the start of this routine, the position should be lined up
+        // at the first byte of a handshake message.  Mark this location
+        // so we can return to it after reading the type and length.
+        srcRecord.mark();
+        int msgHdr = srcRecord.getInt();
+        int type = (msgHdr >> 24) & 0x000000FF;
+        int length = msgHdr & 0x00FFFFFF;
+
+        // Create a byte array that has enough space for the handshake
+        // message header and body.
+        byte[] data = new byte[length + 4];
+        srcRecord.reset();
+        srcRecord.get(data, 0, length + 4);
+
+        return (data);
+    }
+
+    /**
+     * Hex-dumps a ByteBuffer to stdout.
+     */
+    private static void dumpByteBuffer(String header, ByteBuffer bBuf) {
+        if (dumpBufs == false) {
+            return;
+        }
+
+        int bufLen = bBuf.remaining();
+        if (bufLen > 0) {
+            bBuf.mark();
+
+            // We expect the position of the buffer to be at the
+            // beginning of a TLS record.  Get the type, version and length.
+            int type = Byte.toUnsignedInt(bBuf.get());
+            int ver_major = Byte.toUnsignedInt(bBuf.get());
+            int ver_minor = Byte.toUnsignedInt(bBuf.get());
+            int recLen = Short.toUnsignedInt(bBuf.getShort());
+
+            log("===== " + header + " (" + tlsRecType(type) + " / " +
+                ver_major + "." + ver_minor + " / " + bufLen + " bytes) =====");
+            bBuf.reset();
+            for (int i = 0; i < bufLen; i++) {
+                if (i != 0 && i % 16 == 0) {
+                    System.out.print("\n");
+                }
+                System.out.format("%02X ", bBuf.get(i));
+            }
+            log("\n===============================================");
+            bBuf.reset();
+        }
+    }
+
+    private static String tlsRecType(int type) {
+        switch (type) {
+            case 20:
+                return "Change Cipher Spec";
+            case 21:
+                return "Alert";
+            case 22:
+                return "Handshake";
+            case 23:
+                return "Application Data";
+            default:
+                return ("Unknown (" + type + ")");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2013, 2017, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 6956398
+ * @summary make ephemeral DH key match the length of the certificate key
+ * @run main/othervm
+ *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1643 267
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=matched
+ *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=legacy
+ *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=1024
+ *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75
+ *
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 233 75
+ *
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1387 139
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=legacy
+ *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1323 107
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=matched
+ *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1643 267
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=1024
+ *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1387 139
+ *
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 361 139
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=legacy
+ *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 297 107
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=matched
+ *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 361 139
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=1024
+ *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 361 139
+ */
+
+/*
+ * This is a simple hack to test key sizes of Diffie-Hellman key exchanging
+ * during SSL/TLS handshaking.
+ *
+ * The record length of DH ServerKeyExchange and ClientKeyExchange.
+ * ServerKeyExchange message are wrapped in ServerHello series messages, which
+ * contains ServerHello, Certificate and ServerKeyExchange message.
+ *
+ *    struct {
+ *        opaque dh_p<1..2^16-1>;
+ *        opaque dh_g<1..2^16-1>;
+ *        opaque dh_Ys<1..2^16-1>;
+ *    } ServerDHParams;     // Ephemeral DH parameters
+ *
+ *    struct {
+ *        select (PublicValueEncoding) {
+ *            case implicit: struct { };
+ *            case explicit: opaque dh_Yc<1..2^16-1>;
+ *        } dh_public;
+ *    } ClientDiffieHellmanPublic;
+ *
+ * Fomr above structures, it is clear that if the DH key size increasing 128
+ * bits (16 bytes), the ServerHello series messages increases 48 bytes
+ * (becuase dh_p, dh_g and dh_Ys each increase 16 bytes) and ClientKeyExchange
+ * increases 16 bytes (because of the size increasing of dh_Yc).
+ *
+ * Here is a summary of the record length in the test case.
+ *
+ *            |  ServerHello Series  |  ClientKeyExchange | ServerHello Anon
+ *   512-bit  |          1259 bytes  |           75 bytes |        233 bytes
+ *   768-bit  |          1323 bytes  |          107 bytes |        297 bytes
+ *  1024-bit  |          1387 bytes  |          139 bytes |        361 bytes
+ *  2048-bit  |          1643 bytes  |          267 bytes |        361 bytes
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.nio.*;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.Security;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+public class DHEKeySizing {
+
+    private final static boolean debug = true;
+
+    // key length bias because of the stripping of leading zero bytes of
+    // negotiated DH keys.
+    //
+    // This is an effort to mimum intermittent failure when we cannot
+    // estimate what's the exact number of leading zero bytes of
+    // negotiated DH keys.
+    private final static int KEY_LEN_BIAS = 6;
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;    // client
+    private SSLEngine ssle2;    // server
+
+    private ByteBuffer appOut1;         // write side of ssle1
+    private ByteBuffer appIn1;          // read side of ssle1
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificates and key used in the test.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIC8jCCAdqgAwIBAgIEUjkuRzANBgkqhkiG9w0BAQUFADA7MR0wGwYDVQQLExRT\n" +
+        "dW5KU1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMw\n" +
+        "HhcNMTMwOTE4MDQzODMxWhcNMTMxMjE3MDQzODMxWjA7MR0wGwYDVQQLExRTdW5K\n" +
+        "U1NFIFRlc3QgU2VyaXZjZTENMAsGA1UEChMESmF2YTELMAkGA1UEBhMCVVMwggEi\n" +
+        "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCO+IGeaskJAvEcYc7pCl9neK3E\n" +
+        "a28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0LKXArpI3thLNK\n" +
+        "QLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO19FbjxAfInJqk\n" +
+        "3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ7MrIOqHPd+8r\n" +
+        "RbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTkM65T1hnnOv5n\n" +
+        "ZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+PqPgWNl3+/AgMB\n" +
+        "AAEwDQYJKoZIhvcNAQEFBQADggEBAAlrP6DFLRPSy0IgQhcI2i56tR/na8pezSte\n" +
+        "ZHcCdaCZPDy4UP8mpLJ9QCjEB5VJv8hPm4xdK7ULnKGOGHgYqDpV2ZHvQlhV1woQ\n" +
+        "TZGb/LM3c6kAs0j4j9KM2fq3iYUYexjIkS1KzsziflxMM6igS9BRMBR2LQyU+cYq\n" +
+        "YEsFzkF7Aj2ET4v/+tgot9mRr2NioJcaJkdsPDpMU3IKB1cczfu+OuLQ/GCG0Fqu\n" +
+        "6ijCeCqfnaAbemHbJeVZZ6Qgka3uC2YMntLBmLkhqEo1d9zGYLoh7oWL77y5ibQZ\n" +
+        "LK5/H/zikcu579TWjlDHcqL3arCwBcrtsjSaPrRSWMrWV/6c0qw=\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8
+    static String targetPrivateKey =
+        "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCO+IGeaskJAvEc\n" +
+        "Yc7pCl9neK3Ea28fwWLtChufYNaC9hQfZlUdETWYjV7fZJVJKT/oLzdDNMWuVA0L\n" +
+        "KXArpI3thLNKQLXisdF9hKPlZRDazACL9kWUUtJ0FzpEySK4e8wW/z9FuU6e6iO1\n" +
+        "9FbjxAfInJqk3EDiEhB5g73S2vtvPCxgq2DvWw9TDl/LIqdKG2JCS93koXCCaHmQ\n" +
+        "7MrIOqHPd+8rRbGpatXT9qyHKppUv9ATxVygO4rA794mgCFxpT+fkhz+NEB0twTk\n" +
+        "M65T1hnnOv5nZIxkcjBggt85UlZtnP3b9P7SYxsWIa46Oc38Od2f3YejfVg6B+Pq\n" +
+        "PgWNl3+/AgMBAAECggEAPdb5Ycc4m4A9QBSCRcRpzbyiFLKPh0HDg1n65q4hOtYr\n" +
+        "kAVYTVFTSF/lqGS+Ob3w2YIKujQKSUQrvCc5UHdFuHXMgxKIWbymK0+DAMb9SlYw\n" +
+        "6lkkcWp9gx9E4dnJ/df2SAAxovvrKMuHlL1SFASHhVtPfH2URvSfUaANLDXxyYOs\n" +
+        "8BX0Nr6wazhWjLjXo9yIGnKSvFfB8XisYcA78kEgas43zhmIGCDPqaYyyffOfRbx\n" +
+        "pM1KNwGmlN86iWR1CbwA/wwhcMySWQueS+s7cHbpRqZIYJF9jEeELiwi0vxjealS\n" +
+        "EMuHYedIRFMWaDIq9XyjrvXamHb0Z25jlXBNZHaM0QKBgQDE9adl+zAezR/n79vw\n" +
+        "0XiX2Fx1UEo3ApZHuoA2Q/PcBk+rlKqqQ3IwTcy6Wo648wK7v6Nq7w5nEWcsf0dU\n" +
+        "QA2Ng/AJEev/IfF34x7sKGYxtk1gcE0EuSBA3R+ocEZxnNw1Ryd5nUU24s8d4jCP\n" +
+        "Mkothnyaim+zE2raDlEtVc0CaQKBgQC509av+02Uq5oMjzbQp5PBJfQFjATOQT15\n" +
+        "eefYnVYurkQ1kcVfixkrO2ORhg4SjmI2Z5hJDgGtXdwgidpzkad+R2epS5qLMyno\n" +
+        "lQVpY6bMpEZ7Mos0yQygxnm8uNohEcTExOe+nP5fNJVpzBsGmfeyYOhnPQlf6oqf\n" +
+        "0cHizedb5wKBgQC/l5LyMil6HOGHlhzmIm3jj7VI7QR0hJC5T6N+phVml8ESUDjA\n" +
+        "DYHbmSKouISTRtkG14FY+RiSjCxH7bvuKazFV2289PETquogTA/9e8MFYqfcQwG4\n" +
+        "sXi9gBxWlnj/9a2EKiYtOB5nKLR/BlNkSHA93tAA6N+FXEMZwMmYhxk42QKBgAuY\n" +
+        "HQgD3PZOsqDf+qKQIhbmAFCsSMx5o5VFtuJ8BpmJA/Z3ruHkMuDQpsi4nX4o5hXQ\n" +
+        "5t6AAjjH52kcUMXvK40kdWJJtk3DFnVNfvXxYsHX6hHbuHXFqYUKfSP6QJnZmvZP\n" +
+        "9smcz/4usLfWJUWHK740b6upUkFqx9Vq5/b3s9y3AoGAdM5TW7LkkOFsdMGVAUzR\n" +
+        "9iXmCWElHTK2Pcp/3yqDBHSfiQx6Yp5ANyPnE9NBM0yauCfOyBB2oxLO4Rdv3Rqk\n" +
+        "9V9kyR/YAGr7dJaPcQ7pZX0OpkzgueAOJYPrx5VUzPYUtklYV1ycFZTfKlpFCxT+\n" +
+        "Ei6KUo0NXSdUIcB4yib1J10=";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine("server", 2);
+        ssle2.setUseClientMode(false);
+    }
+
+    private boolean isHandshaking(SSLEngine e) {
+        return (e.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING);
+    }
+
+    private void checkResult(ByteBuffer bbIn, ByteBuffer bbOut,
+            SSLEngineResult result,
+            Status status, HandshakeStatus hsStatus,
+            int consumed, int produced)
+            throws Exception {
+
+        if ((status != null) && (result.getStatus() != status)) {
+            throw new Exception("Unexpected Status: need = " + status +
+                " got = " + result.getStatus());
+        }
+
+        if ((hsStatus != null) && (result.getHandshakeStatus() != hsStatus)) {
+            throw new Exception("Unexpected hsStatus: need = " + hsStatus +
+                " got = " + result.getHandshakeStatus());
+        }
+
+        if ((consumed != -1) && (consumed != result.bytesConsumed())) {
+            throw new Exception("Unexpected consumed: need = " + consumed +
+                " got = " + result.bytesConsumed());
+        }
+
+        if ((produced != -1) && (produced != result.bytesProduced())) {
+            throw new Exception("Unexpected produced: need = " + produced +
+                " got = " + result.bytesProduced());
+        }
+
+        if ((consumed != -1) && (bbIn.position() != result.bytesConsumed())) {
+            throw new Exception("Consumed " + bbIn.position() +
+                " != " + consumed);
+        }
+
+        if ((produced != -1) && (bbOut.position() != result.bytesProduced())) {
+            throw new Exception("produced " + bbOut.position() +
+                " != " + produced);
+        }
+    }
+
+    private void test(String cipherSuite, boolean exportable,
+            int lenServerKeyEx, int lenClientKeyEx) throws Exception {
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        String[] suites = new String [] {cipherSuite};
+
+        ssle1.setEnabledCipherSuites(suites);
+        ssle2.setEnabledCipherSuites(suites);
+
+        log("======================================");
+        log("===================");
+        log("client hello");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        oneToTwo.flip();
+
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result2,
+            Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0);
+        runDelegatedTasks(ssle2);
+        oneToTwo.compact();
+
+        log("===================");
+        log("ServerHello");
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        twoToOne.flip();
+
+        log("Message length of ServerHello series: " + twoToOne.remaining());
+        if (twoToOne.remaining() < (lenServerKeyEx - KEY_LEN_BIAS) ||
+                twoToOne.remaining() > lenServerKeyEx) {
+            throw new Exception(
+                "Expected to generate ServerHello series messages of " +
+                lenServerKeyEx + " bytes, but not " + twoToOne.remaining());
+        }
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_TASK, result2.bytesProduced(), 0);
+        runDelegatedTasks(ssle1);
+        twoToOne.compact();
+
+        log("===================");
+        log("Key Exchange");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+        oneToTwo.flip();
+
+        log("Message length of ClientKeyExchange: " + oneToTwo.remaining());
+        if (oneToTwo.remaining() < (lenClientKeyEx - KEY_LEN_BIAS) ||
+                oneToTwo.remaining() > lenClientKeyEx) {
+            throw new Exception(
+                "Expected to generate ClientKeyExchange message of " +
+                lenClientKeyEx + " bytes, but not " + oneToTwo.remaining());
+        }
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result2,
+            Status.OK, HandshakeStatus.NEED_TASK, result1.bytesProduced(), 0);
+        runDelegatedTasks(ssle2);
+        oneToTwo.compact();
+
+        log("===================");
+        log("Client CCS");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+        oneToTwo.flip();
+
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result2,
+            Status.OK, HandshakeStatus.NEED_UNWRAP,
+            result1.bytesProduced(), 0);
+        oneToTwo.compact();
+
+        log("===================");
+        log("Client Finished");
+        result1 = ssle1.wrap(appOut1, oneToTwo);
+        checkResult(appOut1, oneToTwo, result1,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, 0, -1);
+        oneToTwo.flip();
+
+        result2 = ssle2.unwrap(oneToTwo, appIn2);
+        checkResult(oneToTwo, appIn2, result2,
+            Status.OK, HandshakeStatus.NEED_WRAP,
+            result1.bytesProduced(), 0);
+        oneToTwo.compact();
+
+        log("===================");
+        log("Server CCS");
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.NEED_UNWRAP, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        log("===================");
+        log("Server Finished");
+        result2 = ssle2.wrap(appOut2, twoToOne);
+        checkResult(appOut2, twoToOne, result2,
+            Status.OK, HandshakeStatus.FINISHED, 0, -1);
+        twoToOne.flip();
+
+        result1 = ssle1.unwrap(twoToOne, appIn1);
+        checkResult(twoToOne, appIn1, result1,
+            Status.OK, HandshakeStatus.FINISHED, result2.bytesProduced(), 0);
+        twoToOne.compact();
+
+        log("===================");
+        log("Check Session/Ciphers");
+        String cs = ssle1.getSession().getCipherSuite();
+        if (!cs.equals(suites[0])) {
+            throw new Exception("suites not equal: " + cs + "/" + suites[0]);
+        }
+
+        cs = ssle2.getSession().getCipherSuite();
+        if (!cs.equals(suites[0])) {
+            throw new Exception("suites not equal: " + cs + "/" + suites[0]);
+        }
+
+        log("===================");
+        log("Done with SSL/TLS handshaking");
+    }
+
+    public static void main(String args[]) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        if (args.length != 4) {
+            System.out.println(
+                "Usage: java DHEKeySizing cipher-suite " +
+                "exportable(true|false)\n" +
+                "    size-of-server-hello-record size-of-client-key-exchange");
+            throw new Exception("Incorrect usage!");
+        }
+
+        (new DHEKeySizing()).test(args[0],
+                Boolean.parseBoolean(args[1]),
+                Integer.parseInt(args[2]),
+                Integer.parseInt(args[3]));
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public DHEKeySizing() throws Exception {
+        sslc = getSSLContext();
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext() throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ts = KeyStore.getInstance("JKS");
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ts.load(null, null);
+        ks.load(null, null);
+
+        // import the trused cert
+        ByteArrayInputStream is =
+                    new ByteArrayInputStream(trustedCertStr.getBytes());
+        Certificate trusedCert = cf.generateCertificate(is);
+        is.close();
+        ts.setCertificateEntry("rsa-trusted-2048", trusedCert);
+
+        // generate the private key.
+        String keySpecStr = targetPrivateKey;
+        PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                            Base64.getMimeDecoder().decode(keySpecStr));
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+        Certificate[] chain = new Certificate[1];
+        chain[0] = trusedCert;
+
+        // import the key entry.
+        ks.setKeyEntry("rsa-key-2048", priKey, passphrase, chain);
+
+        // create SSL context
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLSv1");
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        log("AppOut1 = " + appOut1);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngine engine) throws Exception {
+
+        Runnable runnable;
+        while ((runnable = engine.getDelegatedTask()) != null) {
+            log("running delegated task...");
+            runnable.run();
+        }
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/DHKeyExchange/LegacyDHEKeyExchange.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8148108
+ * @summary Disable Diffie-Hellman keys less than 1024 bits
+ * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy LegacyDHEKeyExchange
+ */
+
+import java.io.*;
+import javax.net.ssl.*;
+
+public class LegacyDHEKeyExchange {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        try (SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept()) {
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+
+            throw new Exception(
+                "Leagcy DH keys (< 1024) should be restricted");
+        } catch (SSLHandshakeException she) {
+            // ignore, client should terminate the connection
+        } finally {
+            sslServerSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        String[] suites = new String [] {"TLS_DHE_RSA_WITH_AES_128_CBC_SHA"};
+        sslSocket.setEnabledCipherSuites(suites);
+
+        try {
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+
+            throw new Exception("Leagcy DH keys (< 1024) should be restricted");
+        } catch (SSLHandshakeException she) {
+            // ignore, should be caused by algorithm constraints
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Start the tests.
+         */
+        new LegacyDHEKeyExchange();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    LegacyDHEKeyExchange() throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/DHKeyExchange/UseStrongDHSizes.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2017, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8140436
+ * @modules jdk.crypto.ec
+ * @library /javax/net/ssl/templates
+ * @summary Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS
+ * @run main/othervm UseStrongDHSizes 2048
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe2048 UseStrongDHSizes 2048
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe3072 UseStrongDHSizes 2048
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe4096 UseStrongDHSizes 2048
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe6144 UseStrongDHSizes 2048
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe8192 UseStrongDHSizes 2048
+ * @run main/othervm UseStrongDHSizes 3072
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe3072 UseStrongDHSizes 3072
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe4096 UseStrongDHSizes 3072
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe6144 UseStrongDHSizes 3072
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe8192 UseStrongDHSizes 3072
+ * @run main/othervm UseStrongDHSizes 4096
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe4096 UseStrongDHSizes 4096
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe6144 UseStrongDHSizes 4096
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe8192 UseStrongDHSizes 4096
+ * @run main/othervm UseStrongDHSizes 6144
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe6144 UseStrongDHSizes 6144
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe8192 UseStrongDHSizes 6144
+ * @run main/othervm UseStrongDHSizes 8192
+ * @run main/othervm -Djdk.tls.namedGroups=ffdhe8192 UseStrongDHSizes 8192
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Security;
+import javax.net.ssl.SSLSocket;
+
+public class UseStrongDHSizes extends SSLSocketTemplate {
+    /*
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled unexpectedly.
+        String constraint = "DH keySize < " + Integer.valueOf(args[0]);
+        Security.setProperty("jdk.tls.disabledAlgorithms", constraint);
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        (new UseStrongDHSizes()).run();
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        String ciphers[] = {
+                "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"};
+
+        socket.setEnabledCipherSuites(ciphers);
+        socket.setWantClientAuth(true);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        String ciphers[] = {
+                "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"};
+        socket.setEnabledCipherSuites(ciphers);
+        socket.setUseClientMode(true);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.sh	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,81 @@
+#! /bin/sh
+
+#
+# Copyright (c) 2012, 2018, 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.
+#
+# 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.
+#
+
+# @test
+# @bug 7126889
+# @summary Incorrect SSLEngine debug output
+#
+# ${TESTJAVA} is pointing to the JDK under test.
+#
+# set platform-dependent variables
+
+OS=`uname -s`
+case "$OS" in
+  SunOS | Linux | Darwin | AIX )
+    PS=":"
+    FS="/"
+    ;;
+  CYGWIN* )
+    PS=";"
+    FS="/"
+    ;;
+  Windows* )
+    PS=";"
+    FS="\\"
+    ;;
+  * )
+    echo "Unrecognized system!"
+    exit 1;
+    ;;
+esac
+
+${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -d . \
+    ${TESTSRC}${FS}DebugReportsOneExtraByte.java
+
+STRING='WRITE: TLS10 application_data, length = 8'
+
+echo "Examining debug output for the string:"
+echo "${STRING}"
+echo "========="
+
+${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -Djavax.net.debug=all \
+    -Dtest.src=${TESTSRC} \
+    DebugReportsOneExtraByte 2>&1 | \
+    grep "${STRING}"
+RETVAL=$?
+
+echo "========="
+
+if [ ${RETVAL} -ne 0 ]; then
+    echo "Did NOT see the expected debug output."
+    exit 1
+else
+    echo "Received the expected debug output."
+    exit 0
+fi
+else
+    echo "Received the expected debug output."
+    exit 0
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/GenSSLConfigs/main.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,275 @@
+/*
+ * @test
+ * @build TestThread Traffic Handler ServerHandler ServerThread ClientThread
+ * @run main/othervm/timeout=140 -Djsse.enableCBCProtection=false main
+ * @summary Make sure that different configurations of SSL sockets work
+ * @key randomness
+ */
+
+/*
+ * Copyright (c) 1997, 2011, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.security.SecureRandom;
+import java.security.KeyStore;
+import javax.security.cert.*;
+import java.util.Date;
+import java.util.Vector;
+import java.util.ArrayList;
+
+import javax.net.ssl.*;
+
+public class main
+{
+    // NOTE:  "prng" doesn't need to be a SecureRandom
+
+    private static final SecureRandom   prng
+        = new SecureRandom ();
+    private static SSLContext sslContext;
+
+    private static void usage() {
+        System.err.println (
+            "usage: tests.ssl.main default|random|cipher_suite [nthreads]");
+    }
+
+    /**
+     * Runs a test ... there are a variety of configurations, and the way
+     * they're invoked is subject to change.  This program can support
+     * single and multiple process tests, but by default it's set up for
+     * single process testing.
+     *
+     * <P> The first commandline argument identifies a test configuration.
+     * Currently identified configurations include "default", "random".
+     *
+     * <P> The second commandline argument identifies the number of
+     * client threads to use.
+     */
+    public static void main (String argv [])
+    {
+        String          config;
+        int             NTHREADS;
+
+        initContext();
+        String          supported [] = sslContext.getSocketFactory()
+                            .getSupportedCipherSuites();
+
+        // Strip out any Kerberos Suites for now.
+        ArrayList list = new ArrayList(supported.length);
+        for (int i = 0; i < supported.length; i++) {
+            if (!supported[i].startsWith("TLS_KRB5")) {
+                list.add(supported[i]);
+            }
+        }
+        supported = (String [])list.toArray(new String [0]);
+
+        if (argv.length == 2) {
+            config = argv [0];
+            NTHREADS = Integer.parseInt (argv [1]);
+        } else if (argv.length == 1) {
+            config = argv [0];
+            NTHREADS = 15;
+        } else {
+            /* temporaraly changed to make it run under jtreg with
+             * default configuration, when no input parameters are
+             * given
+             */
+            //usage();
+            //return;
+            config = "default";
+            NTHREADS = supported.length;
+        }
+
+        // More options ... port #. different clnt/svr configs,
+        // cipher suites, etc.
+
+        ServerThread    server = new ServerThread (0, NTHREADS, sslContext);
+        Vector          clients = new Vector (NTHREADS);
+
+        if (!(config.equals("default") || config.equals("random")))
+            supported = new String[] {config};
+
+        System.out.println("Supported cipher suites are:");
+        for(int i=0; i < supported.length; i++) {
+            System.out.println(supported[i]);
+        }
+
+        setConfig (server, config, supported);
+
+        // if (OS != Win95)
+            server.setUseMT (true);
+
+        server.start ();
+        server.waitTillReady ();
+
+        //
+        // iterate over all cipher suites
+        //
+        int             next = 0;
+        int             passes = 0;
+
+        if (usesRandom (config))
+            next = nextUnsignedRandom ();
+
+        for (int i = 0; i < NTHREADS; i++, next++) {
+            ClientThread        client = new ClientThread (server.getServerPort(), sslContext);
+            String              cipher [] = new String [1];
+
+            setConfig (client, config, supported);
+            next = next % supported.length;
+            cipher [0] = supported [next];
+            client.setBasicCipherSuites (cipher);
+
+            //
+            // Win95 has been observed to choke if you throw many
+            // connections at it.  So we make it easy to unthread
+            // everything; it can be handy outside Win95 too.
+            //
+            client.start ();
+            if (!server.getUseMT ()) {
+                waitForClient (client);
+                if (client.passed ())
+                    passes++;
+            } else
+                clients.addElement (client);
+        }
+
+        while (!clients.isEmpty ()) {
+            ClientThread        client;
+
+            client = (ClientThread) clients.elementAt (0);
+            clients.removeElement (client);
+            waitForClient (client);
+            if (client.passed ())
+                passes++;
+        }
+
+        System.out.println ("SUMMARY:  threads = " + NTHREADS
+            + ", passes = " + passes);
+    }
+
+
+    //
+    // Rather than replicating code, a helper function!
+    //
+    private static void waitForClient (Thread client)
+    {
+        while (true)
+            try {
+                client.join ();
+
+                // System.out.println ("Joined:  " + client.getName ());
+                break;
+            } catch (InterruptedException e) {
+                continue;
+            }
+    }
+
+    private static void initContext()
+    {
+        try {
+            String testRoot = System.getProperty("test.src", ".");
+            System.setProperty("javax.net.ssl.trustStore", testRoot
+                                + "/../../../../javax/net/ssl/etc/truststore");
+
+            KeyStore ks = KeyStore.getInstance("JKS");
+            ks.load(new FileInputStream(testRoot
+                                + "/../../../../javax/net/ssl/etc/truststore"),
+                    "passphrase".toCharArray());
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, "passphrase".toCharArray());
+            TrustManagerFactory tmf =
+                TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ks);
+            sslContext = SSLContext.getInstance("SSL");
+            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        } catch (Throwable t) {
+            // oh well; ignore it, the tester presumably intends this
+            System.out.println("Failed to read keystore/truststore file... Continuing");
+            t.printStackTrace();
+        }
+    }
+
+    private static int nextUnsignedRandom ()
+    {
+        int retval = prng.nextInt ();
+
+        if (retval < 0)
+            return -retval;
+        else
+            return retval;
+    }
+
+
+    //
+    // Randomness in testing can be good and bad ... covers more
+    // territory, but not reproducibly.
+    //
+    private static boolean usesRandom (String config)
+    {
+        return config.equalsIgnoreCase ("random");
+    }
+
+
+    private static void setConfig (
+        TestThread      test,
+        String          config,
+        String          supported []
+    )
+    {
+        test.setBasicCipherSuites (supported);
+        test.setOutput (System.out);
+        test.setVerbosity (3);
+
+        if (test instanceof ClientThread) {
+            test.setListenHandshake (true);
+            test.setIterations (20);
+        }
+
+// XXX role reversals !!!
+
+        //
+        // We can establish a reasonable degree of variability
+        // on the test data and configs ... expecting that the
+        // diagnostics will identify any problems that exist.
+        // Client and server must agree on these things.
+        //
+        // Unless we do this, only the SSL nonces and ephemeral
+        // keys will be unpredictable in a given test run.  Those
+        // affect only the utmost innards of SSL, details which
+        // are not visible to applications.
+        //
+        if (usesRandom (config)) {
+            int rand = nextUnsignedRandom ();
+
+            if (test instanceof ClientThread)
+                test.setIterations (rand % 35);
+
+            if ((rand & 0x080) == 0)
+                test.setInitiateHandshake (true);
+//          if ((rand & 0x040) == 0)
+//              test.setDoRenegotiate (true);
+
+            test.setPRNG (new SecureRandom ());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/InputRecord/SSLSocketTimeoutNulls.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4456039
+ * @summary Setting timeouts on SSLSockets immediately return null
+ *      after timeout occurs.  This bug was fixed as part of 4393337,
+ *      but this is another bug we want to check regressions against.
+ * @run main/othervm/timeout=140 SSLSocketTimeoutNulls
+ * @author Brad Wetmore
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class SSLSocketTimeoutNulls {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+        sslSocket.startHandshake();
+
+        sslIS.read();
+        Thread.sleep(10000);  // Stall past the timeout...
+        sslOS.write(85);
+        sslOS.flush();
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        boolean caught = false;
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslSocket.startHandshake();
+
+        sslSocket.setSoTimeout(3000); // The stall timeout.
+
+        sslOS.write(280);
+        sslOS.flush();
+
+        try {
+            if (sslIS.read() == -1);
+                throw new Exception("read == -1");
+        // } catch (InterruptedIOException e) { /* if using < JDK 1.4 */
+        } catch (SocketTimeoutException e) {
+            System.out.println("Caught right exception...");
+            caught = true;
+
+            // Try to read it again after it should be available.
+            Thread.sleep(6500);
+            if (sslIS.read() == 85)
+                System.out.println("Read the right value");
+            else
+                throw new Exception("Test Failed");
+        }
+
+        if (!caught)
+            throw new Exception("Didn't see exception");
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new SSLSocketTimeoutNulls();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SSLSocketTimeoutNulls() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        System.err.println(e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLContextImpl/CustomizedDefaultProtocols.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2013, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7093640
+ * @summary Enable TLS 1.1 and TLS 1.2 by default in client side of SunJSSE
+ * @run main/othervm -Djdk.tls.client.protocols="SSLv3,TLSv1,TLSv1.1"
+ *      CustomizedDefaultProtocols
+ */
+
+import java.security.Security;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+public class CustomizedDefaultProtocols {
+    enum ContextVersion {
+        TLS_CV_01("SSL",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1"}),
+        TLS_CV_02("TLS",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1"}),
+        TLS_CV_03("SSLv3",
+                new String[] {"SSLv3", "TLSv1"}),
+        TLS_CV_04("TLSv1",
+                new String[] {"SSLv3", "TLSv1"}),
+        TLS_CV_05("TLSv1.1",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1"}),
+        TLS_CV_06("TLSv1.2",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}),
+        TLS_CV_07("TLSv1.3",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_08("Default",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1"});
+
+        final String contextVersion;
+        final String[] enabledProtocols;
+        final static String[] supportedProtocols = new String[] {
+                "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
+
+        ContextVersion(String contextVersion, String[] enabledProtocols) {
+            this.contextVersion = contextVersion;
+            this.enabledProtocols = enabledProtocols;
+        }
+    }
+
+    private static boolean checkProtocols(String[] target, String[] expected) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No protocols");
+            success = false;
+        }
+
+        if (!protocolEquals(target, expected)) {
+            System.out.println("\tError: Expected to get protocols " +
+                    Arrays.toString(expected));
+            success = false;
+        }
+        System.out.println("\t  Protocols found " + Arrays.toString(target));
+
+        return success;
+    }
+
+    private static boolean protocolEquals(
+            String[] actualProtocols,
+            String[] expectedProtocols) {
+        if (actualProtocols.length != expectedProtocols.length) {
+            return false;
+        }
+
+        Set<String> set = new HashSet<>(Arrays.asList(expectedProtocols));
+        for (String actual : actualProtocols) {
+            if (set.add(actual)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean checkCipherSuites(String[] target) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No cipher suites");
+            success = false;
+        }
+
+        return success;
+    }
+
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        boolean failed = false;
+        for (ContextVersion cv : ContextVersion.values()) {
+            System.out.println("Checking SSLContext of " + cv.contextVersion);
+            SSLContext context = SSLContext.getInstance(cv.contextVersion);
+
+            // Default SSLContext is initialized automatically.
+            if (!cv.contextVersion.equals("Default")) {
+                // Use default TK, KM and random.
+                context.init((KeyManager[])null, (TrustManager[])null, null);
+            }
+
+            //
+            // Check SSLContext
+            //
+            // Check default SSLParameters of SSLContext
+            System.out.println("\tChecking default SSLParameters");
+            SSLParameters parameters = context.getDefaultSSLParameters();
+
+            String[] protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            String[] ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            // Check supported SSLParameters of SSLContext
+            System.out.println("\tChecking supported SSLParameters");
+            parameters = context.getSupportedSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLEngine
+            //
+            // Check SSLParameters of SSLEngine
+            System.out.println();
+            System.out.println("\tChecking SSLEngine of this SSLContext");
+            System.out.println("\tChecking SSLEngine.getSSLParameters()");
+            SSLEngine engine = context.createSSLEngine();
+            engine.setUseClientMode(true);
+            parameters = engine.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = engine.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = engine.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = engine.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = engine.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLSocket
+            //
+            // Check SSLParameters of SSLSocket
+            System.out.println();
+            System.out.println("\tChecking SSLSocket of this SSLContext");
+            System.out.println("\tChecking SSLSocket.getSSLParameters()");
+            SocketFactory fac = context.getSocketFactory();
+            SSLSocket socket = (SSLSocket)fac.createSocket();
+            parameters = socket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = socket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = socket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = socket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = socket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLServerSocket
+            //
+            // Check SSLParameters of SSLServerSocket
+            System.out.println();
+            System.out.println("\tChecking SSLServerSocket of this SSLContext");
+            System.out.println("\tChecking SSLServerSocket.getSSLParameters()");
+            SSLServerSocketFactory sf = context.getServerSocketFactory();
+            SSLServerSocket ssocket = (SSLServerSocket)sf.createServerSocket();
+            parameters = ssocket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = ssocket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = ssocket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = ssocket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = ssocket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+        }
+
+        if (failed) {
+            throw new Exception("Run into problems, see log for more details");
+        } else {
+            System.out.println("\t... Success");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLContextImpl/CustomizedServerDefaultProtocols.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @summary Test jdk.tls.server.protocols with TLS
+ * @run main/othervm -Djdk.tls.server.protocols="SSLv3,TLSv1,TLSv1.1"
+ *      CustomizedServerDefaultProtocols
+ */
+
+import java.security.Security;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+
+public class CustomizedServerDefaultProtocols {
+
+    final static String[] supportedProtocols = new String[]{
+            "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
+
+    enum ContextVersion {
+        TLS_CV_01("SSL",
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1"},
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_02("TLS",
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1"},
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_03("SSLv3",
+                supportedProtocols,
+                new String[]{"SSLv3", "TLSv1"}),
+        TLS_CV_04("TLSv1",
+                supportedProtocols,
+                new String[]{"SSLv3", "TLSv1"}),
+        TLS_CV_05("TLSv1.1",
+                supportedProtocols,
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1"}),
+        TLS_CV_06("TLSv1.2",
+                supportedProtocols,
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}),
+        TLS_CV_07("TLSv1.3",
+                supportedProtocols,
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_08("Default",
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1"},
+                new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
+
+        final String contextVersion;
+        final String[] serverEnabledProtocols;
+        final String[] clientEnabledProtocols;
+
+        ContextVersion(String contextVersion, String[] serverEnabledProtocols,
+                String[] clientEnabledProtocols) {
+            this.contextVersion = contextVersion;
+            this.serverEnabledProtocols = serverEnabledProtocols;
+            this.clientEnabledProtocols = clientEnabledProtocols;
+        }
+    }
+
+    private static boolean checkProtocols(String[] target, String[] expected) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No protocols");
+            success = false;
+        }
+
+        if (!protocolEquals(target, expected)) {
+            System.out.println("\tError: Expected to get protocols " +
+                    Arrays.toString(expected));
+            success = false;
+        }
+        System.out.println("\t  Protocols found " + Arrays.toString(target));
+        return success;
+    }
+
+    private static boolean protocolEquals(
+            String[] actualProtocols,
+            String[] expectedProtocols) {
+        if (actualProtocols.length != expectedProtocols.length) {
+            return false;
+        }
+
+        Set<String> set = new HashSet<>(Arrays.asList(expectedProtocols));
+        for (String actual : actualProtocols) {
+            if (set.add(actual)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean checkCipherSuites(String[] target) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No cipher suites");
+            success = false;
+        }
+
+        return success;
+    }
+
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        System.out.println("jdk.tls.client.protocols = " +
+                System.getProperty("jdk.tls.client.protocols"));
+        System.out.println("jdk.tls.server.protocols = "+
+                System.getProperty("jdk.tls.server.protocols"));
+        Test();
+    }
+
+    static void Test() throws Exception {
+        boolean failed = false;
+
+        for (ContextVersion cv : ContextVersion.values()) {
+            System.out.println("Checking SSLContext of " + cv.contextVersion);
+            SSLContext context = SSLContext.getInstance(cv.contextVersion);
+
+            // Default SSLContext is initialized automatically.
+            if (!cv.contextVersion.equals("Default")) {
+                // Use default TK, KM and random.
+                context.init(null, null, null);
+            }
+
+            //
+            // Check SSLContext
+            //
+            // Check default SSLParameters of SSLContext
+            System.out.println("\tChecking default SSLParameters");
+            SSLParameters parameters = context.getDefaultSSLParameters();
+
+            String[] protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.clientEnabledProtocols);
+
+            String[] ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            // Check supported SSLParameters of SSLContext
+            System.out.println("\tChecking supported SSLParameters");
+            parameters = context.getSupportedSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLEngine
+            //
+            // Check SSLParameters of SSLEngine
+            System.out.println();
+            System.out.println("\tChecking SSLEngine of this SSLContext");
+            System.out.println("\tChecking SSLEngine.getSSLParameters()");
+            SSLEngine engine = context.createSSLEngine();
+            engine.setUseClientMode(true);
+            parameters = engine.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.clientEnabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = engine.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.clientEnabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = engine.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = engine.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = engine.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLSocket
+            //
+            // Check SSLParameters of SSLSocket
+            System.out.println();
+            System.out.println("\tChecking SSLSocket of this SSLContext");
+            System.out.println("\tChecking SSLSocket.getSSLParameters()");
+            SocketFactory fac = context.getSocketFactory();
+            SSLSocket socket = (SSLSocket) fac.createSocket();
+            parameters = socket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.clientEnabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLSocket.getEnabledProtocols()");
+            protocols = socket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.clientEnabledProtocols);
+
+            System.out.println("\tChecking SSLSocket.getEnabledCipherSuites()");
+            ciphers = socket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLSocket.getSupportedProtocols()");
+            protocols = socket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLSocket.getSupportedCipherSuites()");
+            ciphers = socket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLServerSocket
+            //
+            // Check SSLParameters of SSLServerSocket
+            System.out.println();
+            System.out.println("\tChecking SSLServerSocket of this SSLContext");
+            System.out.println("\tChecking SSLServerSocket.getSSLParameters()");
+            SSLServerSocketFactory sf = context.getServerSocketFactory();
+            SSLServerSocket ssocket = (SSLServerSocket) sf.createServerSocket();
+            parameters = ssocket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.serverEnabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = ssocket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.serverEnabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = ssocket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = ssocket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = ssocket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            if (failed) {
+                throw new Exception("Run into problems, see log for more details");
+            } else {
+                System.out.println("\t... Success");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLContextImpl/DefaultEnabledProtocols.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2013, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7093640
+ * @summary Enable TLS 1.1 and TLS 1.2 by default in client side of SunJSSE
+ * @run main/othervm DefaultEnabledProtocols
+ */
+
+import java.security.Security;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+public class DefaultEnabledProtocols {
+    enum ContextVersion {
+        TLS_CV_01("SSL",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_02("TLS",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_03("SSLv3",
+                new String[] {"SSLv3", "TLSv1"}),
+        TLS_CV_04("TLSv1",
+                new String[] {"SSLv3", "TLSv1"}),
+        TLS_CV_05("TLSv1.1",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1"}),
+        TLS_CV_06("TLSv1.2",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}),
+        TLS_CV_07("TLSv1.3",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_08("Default",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
+
+        final String contextVersion;
+        final String[] enabledProtocols;
+        final static String[] supportedProtocols = new String[] {
+                "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
+
+        ContextVersion(String contextVersion, String[] enabledProtocols) {
+            this.contextVersion = contextVersion;
+            this.enabledProtocols = enabledProtocols;
+        }
+    }
+
+    private static boolean checkProtocols(String[] target, String[] expected) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No protocols");
+            success = false;
+        }
+
+        if (!protocolEquals(target, expected)) {
+            System.out.println("\tError: Expected to get protocols " +
+                    Arrays.toString(expected));
+            success = false;
+        }
+        System.out.println("\t  Protocols found " + Arrays.toString(target));
+
+        return success;
+    }
+
+    private static boolean protocolEquals(
+            String[] actualProtocols,
+            String[] expectedProtocols) {
+        if (actualProtocols.length != expectedProtocols.length) {
+            return false;
+        }
+
+        Set<String> set = new HashSet<>(Arrays.asList(expectedProtocols));
+        for (String actual : actualProtocols) {
+            if (set.add(actual)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean checkCipherSuites(String[] target) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No cipher suites");
+            success = false;
+        }
+
+        return success;
+    }
+
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        boolean failed = false;
+        for (ContextVersion cv : ContextVersion.values()) {
+            System.out.println("Checking SSLContext of " + cv.contextVersion);
+            SSLContext context = SSLContext.getInstance(cv.contextVersion);
+
+            // Default SSLContext is initialized automatically.
+            if (!cv.contextVersion.equals("Default")) {
+                // Use default TK, KM and random.
+                context.init((KeyManager[])null, (TrustManager[])null, null);
+            }
+
+            //
+            // Check SSLContext
+            //
+            // Check default SSLParameters of SSLContext
+            System.out.println("\tChecking default SSLParameters");
+            SSLParameters parameters = context.getDefaultSSLParameters();
+
+            String[] protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            String[] ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            // Check supported SSLParameters of SSLContext
+            System.out.println("\tChecking supported SSLParameters");
+            parameters = context.getSupportedSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLEngine
+            //
+            // Check SSLParameters of SSLEngine
+            System.out.println();
+            System.out.println("\tChecking SSLEngine of this SSLContext");
+            System.out.println("\tChecking SSLEngine.getSSLParameters()");
+            SSLEngine engine = context.createSSLEngine();
+            engine.setUseClientMode(true);
+            parameters = engine.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = engine.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = engine.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = engine.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = engine.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLSocket
+            //
+            // Check SSLParameters of SSLSocket
+            System.out.println();
+            System.out.println("\tChecking SSLSocket of this SSLContext");
+            System.out.println("\tChecking SSLSocket.getSSLParameters()");
+            SocketFactory fac = context.getSocketFactory();
+            SSLSocket socket = (SSLSocket)fac.createSocket();
+            parameters = socket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = socket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = socket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = socket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = socket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLServerSocket
+            //
+            // Check SSLParameters of SSLServerSocket
+            System.out.println();
+            System.out.println("\tChecking SSLServerSocket of this SSLContext");
+            System.out.println("\tChecking SSLServerSocket.getSSLParameters()");
+            SSLServerSocketFactory sf = context.getServerSocketFactory();
+            SSLServerSocket ssocket = (SSLServerSocket)sf.createServerSocket();
+            parameters = ssocket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = ssocket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = ssocket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = ssocket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = ssocket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+        }
+
+        if (failed) {
+            throw new Exception("Run into problems, see log for more details");
+        } else {
+            System.out.println("\t... Success");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLContextImpl/MD2InTrustAnchor.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2011, 2016, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7113275
+ * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
+ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.1
+ * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.1
+ * @run main/othervm MD2InTrustAnchor PKIX TLSv1.2
+ * @run main/othervm MD2InTrustAnchor SunX509 TLSv1.2
+ */
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+
+public class MD2InTrustAnchor {
+
+    /*
+     * Certificates and key used in the test.
+     */
+    // It's a trust anchor signed with MD2 hash function.
+    private static final String TRUSTED_CERT_STR = "-----BEGIN CERTIFICATE-----\n"
+            + "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n"
+            + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n"
+            + "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n"
+            + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n"
+            + "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n"
+            + "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n"
+            + "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n"
+            + "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n"
+            + "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n"
+            + "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n"
+            + "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n"
+            + "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n"
+            + "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n"
+            + "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n"
+            + "-----END CERTIFICATE-----";
+
+    // The certificate issued by above trust anchor, signed with MD5
+    private static final String TARGET_CERT_STR = "-----BEGIN CERTIFICATE-----\n"
+            + "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n"
+            + "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n"
+            + "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n"
+            + "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n"
+            + "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n"
+            + "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n"
+            + "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n"
+            + "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n"
+            + "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n"
+            + "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n"
+            + "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n"
+            + "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n"
+            + "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n"
+            + "yvudOlX4BkVR0l1K\n"
+            + "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8.
+    private static final String TARGET_PRIV_KEY_STR = "MIICdwIBADANBgkqhkiG9w0B\n"
+            + "AQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4F5NVEtFXCbEFcVLRjMp3AL3j\n"
+            + "LswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa9+uHt0Z9Wmh4wjHAZhX5Tm5x\n"
+            + "p4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPMKBpyzK6rusorkwpWywTyvH1s\n"
+            + "016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+KSH9tFt+WQbiojjz9ac49trkv\n"
+            + "Ufu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck5mOIYV4uZK8jfNMSQ8v0tFEe\n"
+            + "IPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+HaY3d76hR5qly+Ys+Ww0CQQDj\n"
+            + "eOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ6t0v/xryVIdvOYcRBvKnqEog\n"
+            + "OH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7ez3TDpU9w1B0JXklcV5HddYsR\n"
+            + "qp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3ML11xwwJBAKsZ+Hur3x0tUY29\n"
+            + "No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDElhIM6Rqv12kwCMuQE9i7vo1o3\n"
+            + "WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXsekdXAA4d2d5zGI7q/aGD9SYU6\n"
+            + "phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRTA5kokFb+E3Gplu29tJvCUpfw\n"
+            + "gBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiEnjWHoKY3axDQ8OU=";
+
+    private static final char PASSPHRASE[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    private static volatile CountDownLatch sync = new CountDownLatch(1);
+
+    /*
+     * Turn on SSL debugging?
+     */
+    private static final boolean DEBUG = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doServerSide() throws Exception {
+        SSLContext context = generateSSLContext(TRUSTED_CERT_STR, TARGET_CERT_STR,
+                TARGET_PRIV_KEY_STR);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+        try (SSLServerSocket sslServerSocket
+                = (SSLServerSocket) sslssf.createServerSocket(serverPort)) {
+            sslServerSocket.setNeedClientAuth(true);
+            serverPort = sslServerSocket.getLocalPort();
+            /*
+            * Signal Client, we're ready for his connect.
+             */
+            System.out.println("Signal server ready");
+            sync.countDown();
+
+            System.out.println("Waiting for client connection");
+            try (SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept()) {
+                InputStream sslIS = sslSocket.getInputStream();
+                OutputStream sslOS = sslSocket.getOutputStream();
+
+                sslIS.read();
+                sslOS.write('A');
+                sslOS.flush();
+            }
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        System.out.println("Waiting for server ready");
+        sync.await();
+
+        SSLContext context = generateSSLContext(TRUSTED_CERT_STR, TARGET_CERT_STR,
+                TARGET_PRIV_KEY_STR);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        System.out.println("Connect to server on port: " + serverPort);
+        try (SSLSocket sslSocket
+                = (SSLSocket) sslsf.createSocket("localhost", serverPort)) {
+            // enable the specified TLS protocol
+            sslSocket.setEnabledProtocols(new String[]{tlsProtocol});
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;        // trust manager
+    private static String tlsProtocol;        // trust manager
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        tlsProtocol = args[1];
+    }
+
+    private static SSLContext generateSSLContext(String trustedCertStr,
+            String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trustedCertStr != null) {
+            is = new ByteArrayInputStream(trustedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("RSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                    Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey
+                    = (RSAPrivateKey) kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            // It's not allowed to send MD2 signed certificate to peer,
+            // even it may be a trusted certificate. Then we will not
+            // place the trusted certficate in the chain.
+            Certificate[] chain = new Certificate[1];
+            chain[0] = keyCert;
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, PASSPHRASE, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance(tlsProtocol);
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, PASSPHRASE);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+    // use any free port by default
+    private volatile int serverPort = 0;
+
+    private volatile Exception serverException = null;
+
+    public static void main(String[] args) throws Exception {
+        // MD5 is used in this test case, don't disable MD5 algorithm.
+        Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "MD2, RSA keySize < 1024");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        if (DEBUG) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+        /*
+         * Start the tests.
+         */
+        new MD2InTrustAnchor().runTest();
+    }
+
+    private Thread serverThread = null;
+
+    /*
+     * Used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    public void runTest() throws Exception {
+        startServerThread();
+        doClientSide();
+
+        /*
+         * Wait for other side to close down.
+         */
+        serverThread.join();
+
+        if (serverException != null) {
+            throw serverException;
+        }
+    }
+
+    private void startServerThread() {
+        serverThread = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    doServerSide();
+                } catch (Exception e) {
+                    /*
+                     * Our server thread just died.
+                     *
+                     * Release the client, if not active already...
+                     */
+                    System.err.println("Server died...");
+                    e.printStackTrace(System.out);
+                    serverException = e;
+                    sync.countDown();
+                }
+            }
+        };
+
+        serverThread.start();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLContextImpl/NoOldVersionContext.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2013, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7093640
+ * @summary Enable TLS 1.1 and TLS 1.2 by default in client side of SunJSSE
+ * @run main/othervm -Djdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2"
+ *      NoOldVersionContext
+ */
+
+import java.security.Security;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+
+public class NoOldVersionContext {
+    static enum ContextVersion {
+        TLS_CV_01("SSL",
+                new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"}),
+        TLS_CV_02("TLS",
+                new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"}),
+        TLS_CV_03("SSLv3",
+                new String[] {"SSLv3", "TLSv1"}),
+        TLS_CV_04("TLSv1",
+                new String[] {"SSLv3", "TLSv1"}),
+        TLS_CV_05("TLSv1.1",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1"}),
+        TLS_CV_06("TLSv1.2",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}),
+        TLS_CV_07("TLSv1.3",
+                new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}),
+        TLS_CV_08("Default",
+                new String[] {"TLSv1", "TLSv1.1", "TLSv1.2"});
+
+        final String contextVersion;
+        final String[] enabledProtocols;
+        final static String[] supportedProtocols = new String[] {
+                "SSLv2Hello", "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"};
+
+        ContextVersion(String contextVersion, String[] enabledProtocols) {
+            this.contextVersion = contextVersion;
+            this.enabledProtocols = enabledProtocols;
+        }
+    }
+
+    private static boolean checkProtocols(String[] target, String[] expected) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No protocols");
+            success = false;
+        }
+
+        if (!protocolEquals(target, expected)) {
+            System.out.println("\tError: Expected to get protocols " +
+                    Arrays.toString(expected));
+            System.out.println("\tError: The actual protocols " +
+                    Arrays.toString(target));
+            success = false;
+        }
+
+        return success;
+    }
+
+    private static boolean protocolEquals(
+            String[] actualProtocols,
+            String[] expectedProtocols) {
+        if (actualProtocols.length != expectedProtocols.length) {
+            return false;
+        }
+
+        Set<String> set = new HashSet<>(Arrays.asList(expectedProtocols));
+        for (String actual : actualProtocols) {
+            if (set.add(actual)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    private static boolean checkCipherSuites(String[] target) {
+        boolean success = true;
+        if (target.length == 0) {
+            System.out.println("\tError: No cipher suites");
+            success = false;
+        }
+
+        return success;
+    }
+
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        boolean failed = false;
+        for (ContextVersion cv : ContextVersion.values()) {
+            System.out.println("Checking SSLContext of " + cv.contextVersion);
+            SSLContext context = SSLContext.getInstance(cv.contextVersion);
+
+            // Default SSLContext is initialized automatically.
+            if (!cv.contextVersion.equals("Default")) {
+                // Use default TK, KM and random.
+                context.init((KeyManager[])null, (TrustManager[])null, null);
+            }
+
+            //
+            // Check SSLContext
+            //
+            // Check default SSLParameters of SSLContext
+            System.out.println("\tChecking default SSLParameters");
+            SSLParameters parameters = context.getDefaultSSLParameters();
+
+            String[] protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            String[] ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            // Check supported SSLParameters of SSLContext
+            System.out.println("\tChecking supported SSLParameters");
+            parameters = context.getSupportedSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLEngine
+            //
+            // Check SSLParameters of SSLEngine
+            System.out.println();
+            System.out.println("\tChecking SSLEngine of this SSLContext");
+            System.out.println("\tChecking SSLEngine.getSSLParameters()");
+            SSLEngine engine = context.createSSLEngine();
+            engine.setUseClientMode(true);
+            parameters = engine.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = engine.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = engine.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = engine.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = engine.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLSocket
+            //
+            // Check SSLParameters of SSLSocket
+            System.out.println();
+            System.out.println("\tChecking SSLSocket of this SSLContext");
+            System.out.println("\tChecking SSLSocket.getSSLParameters()");
+            SocketFactory fac = context.getSocketFactory();
+            SSLSocket socket = (SSLSocket)fac.createSocket();
+            parameters = socket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = socket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.enabledProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = socket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = socket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = socket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            //
+            // Check SSLServerSocket
+            //
+            // Check SSLParameters of SSLServerSocket
+            System.out.println();
+            System.out.println("\tChecking SSLServerSocket of this SSLContext");
+            System.out.println("\tChecking SSLServerSocket.getSSLParameters()");
+            SSLServerSocketFactory sf = context.getServerSocketFactory();
+            SSLServerSocket ssocket = (SSLServerSocket)sf.createServerSocket();
+            parameters = ssocket.getSSLParameters();
+
+            protocols = parameters.getProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            ciphers = parameters.getCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getEnabledProtocols()");
+            protocols = ssocket.getEnabledProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println("\tChecking SSLEngine.getEnabledCipherSuites()");
+            ciphers = ssocket.getEnabledCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+
+            System.out.println("\tChecking SSLEngine.getSupportedProtocols()");
+            protocols = ssocket.getSupportedProtocols();
+            failed |= !checkProtocols(protocols, cv.supportedProtocols);
+
+            System.out.println(
+                    "\tChecking SSLEngine.getSupportedCipherSuites()");
+            ciphers = ssocket.getSupportedCipherSuites();
+            failed |= !checkCipherSuites(ciphers);
+        }
+
+        if (failed) {
+            throw new Exception("Run into problems, see log for more details");
+        } else {
+            System.out.println("\t... Success");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLContextImpl/TrustTrustedCert.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2011, 2018, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7113275 8164846
+ * @summary compatibility issue with MD2 trust anchor and old X509TrustManager
+ * @library /javax/net/ssl/templates
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.1 true
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.1 false
+ * @run main/othervm TrustTrustedCert SunX509 TLSv1.1 false
+ * @run main/othervm TrustTrustedCert PKIX TLSv1.2 false
+ * @run main/othervm TrustTrustedCert SunX509 TLSv1.2 false
+ */
+
+import java.net.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+public class TrustTrustedCert extends SSLSocketTemplate {
+
+    /*
+     * Certificates and key used in the test.
+     */
+
+    // It's a trust anchor signed with MD2 hash function.
+    static String trustedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTExMTE4MTExNDA0WhcNMzIxMDI4MTExNDA0WjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBAPGyB9tugUGgxtdeqe0qJEwf9x1Gy4BOi1yR\n" +
+        "wzDZY4H5LquvIfQ2V3J9X1MQENVsFvkvp65ZcFcy+ObOucXUUPFcd/iw2DVb5QXA\n" +
+        "ffyeVqWD56GPi8Qe37wrJO3L6fBhN9oxp/BbdRLgjU81zx8qLEyPODhPMxV4OkcA\n" +
+        "SDwZTSxxAgMBAAGjgaUwgaIwHQYDVR0OBBYEFLOAtr/YrYj9H04EDLA0fd14jisF\n" +
+        "MGMGA1UdIwRcMFqAFLOAtr/YrYj9H04EDLA0fd14jisFoT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
+        "BQADgYEAr8ExpXu/FTIRiMzPm0ubqwME4lniilwQUiEOD/4DbksNjEIcUyS2hIk1\n" +
+        "qsmjJz3SHBnwhxl9dhJVwk2tZLkPGW86Zn0TPVRsttK4inTgCC9GFGeqQBdrU/uf\n" +
+        "lipBzXWljrfbg4N/kK8m2LabtKUMMnGysM8rN0Fx2PYm5xxGvtM=\n" +
+        "-----END CERTIFICATE-----";
+
+    // The certificate issued by above trust anchor, signed with MD5
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICeDCCAeGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTExMTE4MTExNDA2WhcNMzEwODA1MTExNDA2WjBPMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEjAQBgNV\n" +
+        "BAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwDnm96mw\n" +
+        "fXCH4bgXk1US0VcJsQVxUtGMyncAveMuzBzNzOmKZPeqyYX1Fuh4q+cuza03WTJd\n" +
+        "G9nOkNr364e3Rn1aaHjCMcBmFflObnGnhhufNmIGYogJ9dJPmhUVPEVAXrMG+Ces\n" +
+        "NKy2E8woGnLMrqu6yiuTClbLBPK8fWzTXrECAwEAAaN4MHYwCwYDVR0PBAQDAgPo\n" +
+        "MB0GA1UdDgQWBBSdRrpocLPJXyGfDmMWJrcEf29WGDAfBgNVHSMEGDAWgBSzgLa/\n" +
+        "2K2I/R9OBAywNH3deI4rBTAnBgNVHSUEIDAeBggrBgEFBQcDAQYIKwYBBQUHAwIG\n" +
+        "CCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GBAKJ71ZiCUykkJrCLYUxlFlhvUcr9\n" +
+        "sTcOc67QdroW5f412NI15SXWDiley/JOasIiuIFPjaJBjOKoHOvTjG/snVu9wEgq\n" +
+        "YNR8dPsO+NM8r79C6jO+Jx5fYAC7os2XxS75h3NX0ElJcbwIXGBJ6xRrsFh/BGYH\n" +
+        "yvudOlX4BkVR0l1K\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8.
+    static String targetPrivateKey =
+        "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMA55vepsH1wh+G4\n" +
+        "F5NVEtFXCbEFcVLRjMp3AL3jLswczczpimT3qsmF9RboeKvnLs2tN1kyXRvZzpDa\n" +
+        "9+uHt0Z9Wmh4wjHAZhX5Tm5xp4YbnzZiBmKICfXST5oVFTxFQF6zBvgnrDSsthPM\n" +
+        "KBpyzK6rusorkwpWywTyvH1s016xAgMBAAECgYEAn9bF3oRkdDoBU0i/mcww5I+K\n" +
+        "SH9tFt+WQbiojjz9ac49trkvUfu7MO1Jui2+QbrvaSkyj+HYGFOJd1wMsPXeB7ck\n" +
+        "5mOIYV4uZK8jfNMSQ8v0tFEeIPp5lKdw1XnrQfSe+abo2eL5Lwso437Y4s3w37+H\n" +
+        "aY3d76hR5qly+Ys+Ww0CQQDjeOoX89d/xhRqGXKjCx8ImE/dPmsI8O27cwtKrDYJ\n" +
+        "6t0v/xryVIdvOYcRBvKnqEogOH7T1kI+LnWKUTJ2ehJ7AkEA2FVloPVqCehXcc7e\n" +
+        "z3TDpU9w1B0JXklcV5HddYsRqp9RukN/VK4szKE7F1yoarIUtfE9Lr9082Jwyp3M\n" +
+        "L11xwwJBAKsZ+Hur3x0tUY29No2Nf/pnFyvEF57SGwA0uPmiL8Ol9lpz+UDudDEl\n" +
+        "hIM6Rqv12kwCMuQE9i7vo1o3WU3k5KECQEqhg1L49yD935TqiiFFpe0Ur9btQXse\n" +
+        "kdXAA4d2d5zGI7q/aGD9SYU6phkUJSHR16VA2RuUfzMrpb+wmm1IrmMCQFtLoKRT\n" +
+        "A5kokFb+E3Gplu29tJvCUpfwgBFRS+wmkvtiaU/tiyDcVgDO+An5DwedxxdVzqiE\n" +
+        "njWHoKY3axDQ8OU=\n";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    @Override
+    protected SSLContext createServerSSLContext() throws Exception {
+        return generateSSLContext();
+    }
+
+    @Override
+    protected void configureServerSocket(SSLServerSocket socket) {
+        socket.setNeedClientAuth(true);
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        try {
+            sslIS.read();
+            sslOS.write('A');
+            sslOS.flush();
+        } catch (SSLException ssle) {
+            if (!expectFail) {
+                throw ssle;
+            }   // Otherwise, ignore.
+        }
+    }
+
+    @Override
+    protected SSLContext createClientSSLContext() throws Exception {
+        return generateSSLContext();
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        // enable the specified TLS protocol
+        socket.setEnabledProtocols(new String[] { tlsProtocol });
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        try {
+            sslOS.write('B');
+            sslOS.flush();
+            sslIS.read();
+        } catch (SSLHandshakeException e) {
+            if (expectFail) {
+            // focus on the CertPathValidatorException
+                Throwable t = e.getCause().getCause();
+                if (t == null || !t.toString().contains("MD5withRSA")) {
+                    throw new RuntimeException(
+                        "Expected to see MD5withRSA in exception output", t);
+                }
+            } else {
+                throw e;
+            }
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+    private static String tmAlgorithm;        // trust manager
+    private static String tlsProtocol;        // trust manager
+    // set this flag to test context of CertificateException
+    private static boolean expectFail;
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+        tlsProtocol = args[1];
+        expectFail = Boolean.parseBoolean(args[2]);
+    }
+
+    private static SSLContext generateSSLContext() throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        X509Certificate trusedCert = null;
+        ByteArrayInputStream is =
+                new ByteArrayInputStream(trustedCertStr.getBytes());
+        trusedCert = (X509Certificate)cf.generateCertificate(is);
+        is.close();
+
+        ks.setCertificateEntry("Trusted RSA Signer", trusedCert);
+
+        // generate the private key.
+        PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                            Base64.getMimeDecoder().decode(targetPrivateKey));
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKey priKey =
+                (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+        // generate certificate chain
+        is = new ByteArrayInputStream(targetCertStr.getBytes());
+        X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is);
+        is.close();
+
+        X509Certificate[] chain = new X509Certificate[2];
+        chain[0] = keyCert;
+        chain[1] = trusedCert;
+
+        // import the key entry and the chain
+        ks.setKeyEntry("TheKey", priKey, passphrase, chain);
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        // create the customized KM and TM
+        NoneExtendedX509TM myTM =
+            new NoneExtendedX509TM(tmf.getTrustManagers()[0]);
+        NoneExtendedX509KM myKM =
+            new NoneExtendedX509KM("TheKey", chain, priKey);
+
+        SSLContext ctx = SSLContext.getInstance(tlsProtocol);
+        // KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        // kmf.init(ks, passphrase);
+        // ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        ctx.init(new KeyManager[]{myKM}, new TrustManager[]{myTM}, null);
+        ks = null;
+
+        return ctx;
+    }
+
+    static class NoneExtendedX509TM implements X509TrustManager {
+        X509TrustManager tm;
+
+        NoneExtendedX509TM(TrustManager tm) {
+            this.tm = (X509TrustManager)tm;
+        }
+
+        public void checkClientTrusted(X509Certificate chain[], String authType)
+                throws CertificateException {
+            tm.checkClientTrusted(chain, authType);
+        }
+
+        public void checkServerTrusted(X509Certificate chain[], String authType)
+                throws CertificateException {
+            tm.checkServerTrusted(chain, authType);
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            return tm.getAcceptedIssuers();
+        }
+    }
+
+    static class NoneExtendedX509KM implements X509KeyManager {
+        private String keyAlias;
+        private X509Certificate[] chain;
+        private PrivateKey privateKey;
+
+        NoneExtendedX509KM(String keyAlias, X509Certificate[] chain,
+                PrivateKey privateKey) {
+            this.keyAlias = keyAlias;
+            this.chain = chain;
+            this.privateKey = privateKey;
+        }
+
+        public String[] getClientAliases(String keyType, Principal[] issuers) {
+            return new String[] {keyAlias};
+        }
+
+        public String chooseClientAlias(String[] keyType, Principal[] issuers,
+                Socket socket) {
+            return keyAlias;
+        }
+
+        public String[] getServerAliases(String keyType, Principal[] issuers) {
+            return new String[] {keyAlias};
+        }
+
+        public String chooseServerAlias(String keyType, Principal[] issuers,
+                Socket socket) {
+            return keyAlias;
+        }
+
+        public X509Certificate[] getCertificateChain(String alias) {
+            return chain;
+        }
+
+        public PrivateKey getPrivateKey(String alias) {
+            return privateKey;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * MD5 is used in this test case, don't disable MD5 algorithm.
+         * if expectFail is set, we're testing exception message
+         */
+        if (!expectFail) {
+            Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "MD2, RSA keySize < 1024");
+        }
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        /*
+         * Start the tests.
+         */
+        new TrustTrustedCert().run();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/CloseEngineException.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4969799
+ * @summary javax.net.ssl.SSLSocket.SSLSocket(InetAddress,int) shouldn't
+ *              throw exception
+ * @run main/othervm CloseEngineException
+ */
+
+//
+// This is making sure that starting a new handshake throws the right
+// exception.  There is a similar test for SSLSocket.
+//
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+// Note that this test case depends on JSSE provider implementation details.
+public class CloseEngineException {
+
+    private static boolean debug = true;
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;    // client
+    private SSLEngine ssle2;    // server
+
+    private static String pathToStores = "../../../../javax/net/ssl/etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer appOut1;         // write side of ssle1
+    private ByteBuffer appIn1;          // read side of ssle1
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine();
+        ssle2.setUseClientMode(false);
+        ssle2.setNeedClientAuth(true);
+    }
+
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        while (!isEngineClosed(ssle1) && !isEngineClosed(ssle2)) {
+
+            log("================");
+
+            if (!isEngineClosed(ssle1)) {
+                result1 = ssle1.wrap(appOut1, oneToTwo);
+                runDelegatedTasks(result1, ssle1);
+
+                log("wrap1:  " + result1);
+                log("oneToTwo  = " + oneToTwo);
+                log("");
+
+                oneToTwo.flip();
+            }
+            if (!isEngineClosed(ssle2)) {
+                result2 = ssle2.wrap(appOut2, twoToOne);
+                runDelegatedTasks(result2, ssle2);
+
+                log("wrap2:  " + result2);
+                log("twoToOne  = " + twoToOne);
+
+                twoToOne.flip();
+            }
+
+            log("----");
+
+            if (!isEngineClosed(ssle1) && !dataDone) {
+            log("--");
+                result1 = ssle1.unwrap(twoToOne, appIn1);
+                runDelegatedTasks(result1, ssle1);
+
+                log("unwrap1: " + result1);
+                log("twoToOne  = " + twoToOne);
+                log("");
+
+                twoToOne.compact();
+            }
+            if (!isEngineClosed(ssle2)) {
+            log("---");
+                result2 = ssle2.unwrap(oneToTwo, appIn2);
+                runDelegatedTasks(result2, ssle2);
+
+                log("unwrap2: " + result2);
+                log("oneToTwo  = " + oneToTwo);
+
+                oneToTwo.compact();
+            }
+
+            /*
+             * If we've transfered all the data between app1 and app2,
+             * we try to close and see what that gets us.
+             */
+            if (!dataDone && (appOut1.limit() == appIn2.position()) &&
+                    (appOut2.limit() == appIn1.position())) {
+
+                checkTransfer(appOut1, appIn2);
+                checkTransfer(appOut2, appIn1);
+
+                log("Closing ssle1's *OUTBOUND*...");
+                ssle1.closeOutbound();
+                dataDone = true;
+
+                try {
+                    /*
+                     * Check that closed Outbound generates.
+                     */
+                    ssle1.beginHandshake();
+                    throw new Exception(
+                        "TEST FAILED:  didn't throw Exception");
+                } catch (SSLException e) {
+                    System.err.println("PARTIAL PASS");
+                }
+            }
+        }
+
+        try {
+            /*
+             * Check that closed Inbound generates.
+             */
+            ssle2.beginHandshake();
+            throw new Exception(
+                "TEST FAILED:  didn't throw Exception");
+        } catch (SSLException e) {
+            System.err.println("TEST PASSED");
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        CloseEngineException test;
+
+        test = new CloseEngineException();
+
+        test.createSSLEngines();
+
+        test.runTest();
+
+        System.err.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public CloseEngineException() throws Exception {
+        sslc = getSSLContext(keyFilename, trustFilename);
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext(String keyFile, String trustFile)
+            throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        log("AppOut1 = " + appOut1);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("running delegated task...");
+                runnable.run();
+            }
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("Data transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.err.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/CloseStart.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2004, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 5019096
+ * @summary Add scatter/gather APIs for SSLEngine
+ * @run main/othervm CloseStart
+ */
+
+//
+// Check to see if the args are being parsed properly.
+//
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class CloseStart {
+
+    private static boolean debug = false;
+
+    private static String pathToStores = "../../../../javax/net/ssl/etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private static void checkDone(SSLEngine ssle) throws Exception {
+        if (!ssle.isInboundDone()) {
+            throw new Exception("isInboundDone isn't done");
+        }
+        if (!ssle.isOutboundDone()) {
+            throw new Exception("isOutboundDone isn't done");
+        }
+    }
+
+    private static void runTest2(SSLEngine ssle) throws Exception {
+        ssle.closeOutbound();
+        checkDone(ssle);
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        SSLEngine ssle = createSSLEngine(keyFilename, trustFilename);
+        ssle.closeInbound();
+        if (!ssle.isInboundDone()) {
+            throw new Exception("isInboundDone isn't done");
+        }
+
+        ssle = createSSLEngine(keyFilename, trustFilename);
+        ssle.closeOutbound();
+        if (!ssle.isOutboundDone()) {
+            throw new Exception("isOutboundDone isn't done");
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    static private SSLEngine createSSLEngine(String keyFile, String trustFile)
+            throws Exception {
+
+        SSLEngine ssle;
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        ssle = sslCtx.createSSLEngine("client", 1001);
+        ssle.setUseClientMode(true);
+
+        return ssle;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2004, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4980882 8207250
+ * @summary SSLEngine should enforce setUseClientMode
+ * @run main/othervm EngineEnforceUseClientMode
+ * @author Brad R. Wetmore
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class EngineEnforceUseClientMode {
+
+    private static boolean debug = false;
+
+    private SSLContext sslc;
+    private SSLEngine ssle1;    // client
+    private SSLEngine ssle2;    // server
+
+    private SSLEngine ssle3;    // server
+    private SSLEngine ssle4;    // server
+    private SSLEngine ssle5;    // server
+
+    private static String pathToStores = "../../../../javax/net/ssl/etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private ByteBuffer appOut1;         // write side of ssle1
+    private ByteBuffer appIn1;          // read side of ssle1
+    private ByteBuffer appOut2;         // write side of ssle2
+    private ByteBuffer appIn2;          // read side of ssle2
+
+    private ByteBuffer oneToTwo;        // "reliable" transport ssle1->ssle2
+    private ByteBuffer twoToOne;        // "reliable" transport ssle2->ssle1
+
+    /*
+     * Majority of the test case is here, setup is done below.
+     */
+    private void createSSLEngines() throws Exception {
+        ssle1 = sslc.createSSLEngine("client", 1);
+        ssle1.setUseClientMode(true);
+
+        ssle2 = sslc.createSSLEngine();
+        ssle2.setUseClientMode(false);
+        ssle2.setNeedClientAuth(true);
+
+        /*
+         * Note, these are not initialized to client/server
+         */
+        ssle3 = sslc.createSSLEngine();
+        ssle4 = sslc.createSSLEngine();
+        ssle5 = sslc.createSSLEngine();
+    }
+
+    private void runTest() throws Exception {
+
+        createSSLEngines();
+        createBuffers();
+
+        /*
+         * First try the engines with no client/server initialization
+         * All should fail.
+         */
+        try {
+            System.out.println("Testing wrap()");
+            ssle3.wrap(appOut1, oneToTwo);
+            throw new RuntimeException(
+                "wrap():  Didn't catch the exception properly");
+        } catch (IllegalStateException e) {
+            System.out.println("Caught the correct exception.");
+            oneToTwo.flip();
+            if (oneToTwo.hasRemaining()) {
+                throw new Exception("wrap generated data");
+            }
+            oneToTwo.clear();
+        }
+
+        try {
+            System.out.println("Testing unwrap()");
+            ssle4.unwrap(oneToTwo, appIn1);
+            throw new RuntimeException(
+                "unwrap():  Didn't catch the exception properly");
+        } catch (IllegalStateException e) {
+            System.out.println("Caught the correct exception.");
+            appIn1.flip();
+            if (appIn1.hasRemaining()) {
+                throw new Exception("unwrap generated data");
+            }
+            appIn1.clear();
+        }
+
+        try {
+            System.out.println("Testing beginHandshake()");
+            ssle5.beginHandshake();
+            throw new RuntimeException(
+                "unwrap():  Didn't catch the exception properly");
+        } catch (IllegalStateException e) {
+            System.out.println("Caught the correct exception.");
+        }
+
+        boolean dataDone = false;
+
+        SSLEngineResult result1;        // ssle1's results from last operation
+        SSLEngineResult result2;        // ssle2's results from last operation
+
+        while (!isEngineClosed(ssle1) || !isEngineClosed(ssle2)) {
+
+            log("================");
+
+            result1 = ssle1.wrap(appOut1, oneToTwo);
+            result2 = ssle2.wrap(appOut2, twoToOne);
+
+            log("wrap1:  " + result1);
+            log("oneToTwo  = " + oneToTwo);
+            log("");
+
+            log("wrap2:  " + result2);
+            log("twoToOne  = " + twoToOne);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.flip();
+            twoToOne.flip();
+
+            log("----");
+
+            result1 = ssle1.unwrap(twoToOne, appIn1);
+            result2 = ssle2.unwrap(oneToTwo, appIn2);
+
+            log("unwrap1: " + result1);
+            log("twoToOne  = " + twoToOne);
+            log("");
+
+            log("unwrap2: " + result2);
+            log("oneToTwo  = " + oneToTwo);
+
+            runDelegatedTasks(result1, ssle1);
+            runDelegatedTasks(result2, ssle2);
+
+            oneToTwo.compact();
+            twoToOne.compact();
+
+            /*
+             * If we've transfered all the data between app1 and app2,
+             * we try to close and see what that gets us.
+             */
+            if (!dataDone && (appOut1.limit() == appIn2.position()) &&
+                    (appOut2.limit() == appIn1.position())) {
+
+                checkTransfer(appOut1, appIn2);
+                checkTransfer(appOut2, appIn1);
+
+                // Should not be able to set mode now, no matter if
+                // it is the same of different.
+                System.out.println("Try changing modes...");
+                for (boolean b : new Boolean[] {true, false}) {
+                    try {
+                        ssle2.setUseClientMode(b);
+                        throw new RuntimeException(
+                                "setUseClientMode(" + b + "):  " +
+                                        "Didn't catch the exception properly");
+                    } catch (IllegalArgumentException e) {
+                        System.out.println("Caught the correct exception.");
+                    }
+                }
+
+                return;
+            }
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        EngineEnforceUseClientMode test;
+
+        test = new EngineEnforceUseClientMode();
+
+        test.createSSLEngines();
+
+        test.runTest();
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * **********************************************************
+     * Majority of the test case is above, below is just setup stuff
+     * **********************************************************
+     */
+
+    public EngineEnforceUseClientMode() throws Exception {
+        sslc = getSSLContext(keyFilename, trustFilename);
+    }
+
+    /*
+     * Create an initialized SSLContext to use for this test.
+     */
+    private SSLContext getSSLContext(String keyFile, String trustFile)
+            throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFile), passphrase);
+        ts.load(new FileInputStream(trustFile), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+    private void createBuffers() {
+        // Size the buffers as appropriate.
+
+        SSLSession session = ssle1.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        appIn1 = ByteBuffer.allocateDirect(appBufferMax + 50);
+        appIn2 = ByteBuffer.allocateDirect(appBufferMax + 50);
+
+        oneToTwo = ByteBuffer.allocateDirect(netBufferMax);
+        twoToOne = ByteBuffer.allocateDirect(netBufferMax);
+
+        appOut1 = ByteBuffer.wrap("Hi Engine2, I'm SSLEngine1".getBytes());
+        appOut2 = ByteBuffer.wrap("Hello Engine1, I'm SSLEngine2".getBytes());
+
+        log("AppOut1 = " + appOut1);
+        log("AppOut2 = " + appOut2);
+        log("");
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("running delegated task...");
+                runnable.run();
+            }
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("Data transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    private static void log(String str) {
+        if (debug) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/RehandshakeFinished.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 2004, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 6207322
+ * @summary SSLEngine is returning a premature FINISHED message when doing
+ *     an abbreviated handshake.
+ * @run main/othervm RehandshakeFinished
+ * @author Brad Wetmore
+ */
+
+/*
+ * This test may need some updating if the messages change order.
+ * Currently I'm expecting that there is a simple renegotiation, with
+ * each message being contained in a single SSL packet.
+ *
+ *      ClientHello
+ *                              Server Hello
+ *                              CCS
+ *                              FINISHED
+ *      CCS
+ *      FINISHED
+ */
+
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class RehandshakeFinished {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static boolean debug = false;
+
+    static private SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static String pathToStores = "../../../../javax/net/ssl/etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    private static Exception loadException = null;
+
+    static {
+        try {
+            KeyStore ks = KeyStore.getInstance("JKS");
+            KeyStore ts = KeyStore.getInstance("JKS");
+
+            char[] passphrase = "passphrase".toCharArray();
+
+            ks.load(new FileInputStream(keyFilename), passphrase);
+            ts.load(new FileInputStream(trustFilename), passphrase);
+
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+            kmf.init(ks, passphrase);
+
+            TrustManagerFactory tmf =
+                TrustManagerFactory.getInstance("SunX509");
+            tmf.init(ts);
+
+            SSLContext sslCtx = SSLContext.getInstance("TLSv1.2");
+            sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            sslc = sslCtx;
+        } catch (Exception e) {
+            loadException = e;
+        }
+    }
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        if (loadException != null) {
+            throw loadException;
+        }
+
+        // Prime the session cache with a good session
+        // Second connection should be a simple session resumption.
+        if ((new RehandshakeFinished().runTest()) !=
+                new RehandshakeFinished().runRehandshake()) {
+            throw new Exception("Sessions not equivalent");
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    private void checkResult(SSLEngine engine, SSLEngineResult result,
+            HandshakeStatus rqdHsStatus,
+            boolean consumed, boolean produced) throws Exception {
+
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+
+        if (hsStatus == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                runnable.run();
+            }
+            hsStatus = engine.getHandshakeStatus();
+        }
+
+        if (hsStatus != rqdHsStatus) {
+            throw new Exception("Required " + rqdHsStatus +
+                ", got " + hsStatus);
+        }
+
+        int bc = result.bytesConsumed();
+        int bp = result.bytesProduced();
+
+        if (consumed) {
+            if (bc <= 0) {
+                throw new Exception("Should have consumed bytes");
+            }
+        } else {
+            if (bc > 0) {
+                throw new Exception("Should not have consumed bytes");
+            }
+        }
+
+        if (produced) {
+            if (bp <= 0) {
+                throw new Exception("Should have produced bytes");
+            }
+        } else {
+            if (bp > 0) {
+                throw new Exception("Should not have produced bytes");
+            }
+        }
+    }
+
+    private SSLSession runRehandshake() throws Exception {
+
+        log("\n\n==============================================");
+        log("Staring actual test.");
+
+        createSSLEngines();
+        createBuffers();
+        SSLEngineResult result;
+
+        log("Client's ClientHello");
+        checkResult(clientEngine,
+            clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_UNWRAP,
+            false, true);
+        cTOs.flip();
+        checkResult(serverEngine,
+            serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_WRAP,
+            true, false);
+        cTOs.compact();
+
+        log("Server's ServerHello/ServerHelloDone");
+        checkResult(serverEngine,
+            serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP,
+            false, true);
+        sTOc.flip();
+        checkResult(clientEngine,
+            clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_UNWRAP,
+            true, false);
+        sTOc.compact();
+
+        log("Server's CCS");
+        checkResult(serverEngine,
+            serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_WRAP,
+            false, true);
+        sTOc.flip();
+        checkResult(clientEngine,
+            clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_UNWRAP,
+            true, false);
+        sTOc.compact();
+
+        log("Server's FINISHED");
+        checkResult(serverEngine,
+            serverEngine.wrap(serverOut, sTOc), HandshakeStatus.NEED_UNWRAP,
+            false, true);
+        sTOc.flip();
+        checkResult(clientEngine,
+            clientEngine.unwrap(sTOc, clientIn), HandshakeStatus.NEED_WRAP,
+            true, false);
+        sTOc.compact();
+
+        log("Client's CCS");
+        checkResult(clientEngine,
+            clientEngine.wrap(clientOut, cTOs), HandshakeStatus.NEED_WRAP,
+            false, true);
+        cTOs.flip();
+        checkResult(serverEngine,
+            serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.NEED_UNWRAP,
+            true, false);
+        cTOs.compact();
+
+        log("Client's FINISHED should trigger FINISHED messages all around.");
+        checkResult(clientEngine,
+            clientEngine.wrap(clientOut, cTOs), HandshakeStatus.FINISHED,
+            false, true);
+        cTOs.flip();
+        checkResult(serverEngine,
+            serverEngine.unwrap(cTOs, serverIn), HandshakeStatus.FINISHED,
+            true, false);
+        cTOs.compact();
+
+        return clientEngine.getSession();
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private SSLSession runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult clientResult;   // results from client's last operation
+        SSLEngineResult serverResult;   // results from server's last operation
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        while (!isEngineClosed(clientEngine) ||
+                !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("----");
+
+            clientResult = clientEngine.unwrap(sTOc, clientIn);
+            log("client unwrap: ", clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            log("server unwrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                log("\tClosing clientEngine's *OUTBOUND*...");
+                clientEngine.closeOutbound();
+                dataDone = true;
+            }
+        }
+
+        return clientEngine.getSession();
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(true);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/SSLEngineBadBufferArrayAccess.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,616 @@
+/*
+ * Copyright (c) 2011, 2016, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7031830
+ * @summary bad_record_mac failure on TLSv1.2 enabled connection with SSLEngine
+ * @run main/othervm SSLEngineBadBufferArrayAccess
+ */
+
+/**
+ * A SSLSocket/SSLEngine interop test case.  This is not the way to
+ * code SSLEngine-based servers, but works for what we need to do here,
+ * which is to make sure that SSLEngine/SSLSockets can talk to each other.
+ * SSLEngines can use direct or indirect buffers, and different code
+ * is used to get at the buffer contents internally, so we test that here.
+ *
+ * The test creates one SSLSocket (client) and one SSLEngine (server).
+ * The SSLSocket talks to a raw ServerSocket, and the server code
+ * does the translation between byte [] and ByteBuffers that the SSLEngine
+ * can use.  The "transport" layer consists of a Socket Input/OutputStream
+ * and two byte buffers for the SSLEngines:  think of them
+ * as directly connected pipes.
+ *
+ * Again, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      write()         ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      read()         ...             ServerHello/Certificate
+ *      write()         ...             ClientKeyExchange
+ *      write()         ...             ChangeCipherSpec
+ *      write()         ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      read()          ...             ChangeCipherSpec
+ *      read()          ...             Finished
+ *
+ * This particular bug had a problem where byte buffers backed by an
+ * array didn't offset correctly, and we got bad MAC errors.
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.net.*;
+import java.security.*;
+import java.nio.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class SSLEngineBadBufferArrayAccess {
+
+    /*
+     * Enables logging of the SSL/TLS operations.
+     */
+    private static boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static boolean debug = false;
+    private SSLContext sslc;
+    private SSLEngine serverEngine;     // server-side SSLEngine
+
+    private final byte[] serverMsg = "Hi there Client, I'm a Server".getBytes();
+    private final byte[] clientMsg = "Hello Server, I'm a Client".getBytes();
+
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    private volatile Exception clientException;
+    private volatile Exception serverException;
+
+    /*
+     * For data transport, this example uses local ByteBuffers.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores/trust material.
+     */
+    private static final String pathToStores = "../../../../javax/net/ssl/etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final String passwd = "passphrase";
+    private static String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores
+            + "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores
+            + "/" + trustStoreFile;
+
+    /*
+     * Is the server ready to serve?
+     */
+    private static final CountDownLatch serverCondition = new CountDownLatch(1);
+
+    /*
+     * Is the client ready to handshake?
+     */
+    private static final CountDownLatch clientCondition = new CountDownLatch(1);
+
+    /*
+     * What's the server port?  Use any free port by default
+     */
+    private volatile int serverPort = 0;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        String [] protocols = new String [] {
+            "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" };
+
+        for (String protocol : protocols) {
+            /*
+             * Run the tests with direct and indirect buffers.
+             */
+            log("Testing " + protocol + ":true");
+            new SSLEngineBadBufferArrayAccess(protocol).runTest(true);
+
+            log("Testing " + protocol + ":false");
+            new SSLEngineBadBufferArrayAccess(protocol).runTest(false);
+        }
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLEngineBadBufferArrayAccess(String protocol) throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        try (FileInputStream fis = new FileInputStream(keyFilename)) {
+            ks.load(fis, passphrase);
+        }
+
+        try (FileInputStream fis = new FileInputStream(trustFilename)) {
+            ts.load(fis, passphrase);
+        }
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance(protocol);
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, with the server engine calling wrap/unwrap
+     * regardless of whether data is available or not.  We do this until
+     * we get the application data.  Then we shutdown and go to the next one.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest(boolean direct) throws Exception {
+        boolean serverClose = direct;
+
+        ServerSocket serverSocket = new ServerSocket(0);
+        serverPort = serverSocket.getLocalPort();
+
+        // Signal the client, the server is ready to accept connection.
+        serverCondition.countDown();
+
+        Thread clientThread = runClient(serverClose);
+
+        // Try to accept a connection in 30 seconds.
+        Socket socket;
+        try {
+            serverSocket.setSoTimeout(30000);
+            socket = (Socket) serverSocket.accept();
+        } catch (SocketTimeoutException ste) {
+            serverSocket.close();
+
+            // Ignore the test case if no connection within 30 seconds.
+            System.out.println(
+                "No incoming client connection in 30 seconds. " +
+                "Ignore in server side.");
+            return;
+        }
+
+        // handle the connection
+        try {
+            // Is it the expected client connection?
+            //
+            // Naughty test cases or third party routines may try to
+            // connection to this server port unintentionally.  In
+            // order to mitigate the impact of unexpected client
+            // connections and avoid intermittent failure, it should
+            // be checked that the accepted connection is really linked
+            // to the expected client.
+            boolean clientIsReady =
+                    clientCondition.await(30L, TimeUnit.SECONDS);
+
+            if (clientIsReady) {
+                // Run the application in server side.
+                runServerApplication(socket, direct, serverClose);
+            } else {    // Otherwise, ignore
+                // We don't actually care about plain socket connections
+                // for TLS communication testing generally.  Just ignore
+                // the test if the accepted connection is not linked to
+                // the expected client or the client connection timeout
+                // in 30 seconds.
+                System.out.println(
+                        "The client is not the expected one or timeout. " +
+                        "Ignore in server side.");
+            }
+        } catch (Exception e) {
+            System.out.println("Server died ...");
+            e.printStackTrace(System.out);
+            serverException = e;
+        } finally {
+            socket.close();
+            serverSocket.close();
+        }
+
+        clientThread.join();
+
+        if (clientException != null || serverException != null) {
+            throw new RuntimeException("Test failed");
+        }
+    }
+
+    /*
+     * Define the server side application of the test for the specified socket.
+     */
+    void runServerApplication(Socket socket, boolean direct,
+            boolean serverClose) throws Exception {
+
+        socket.setSoTimeout(500);
+
+        createSSLEngine();
+        createBuffers(direct);
+
+        boolean closed = false;
+
+        InputStream is = socket.getInputStream();
+        OutputStream os = socket.getOutputStream();
+
+        SSLEngineResult serverResult;   // results from last operation
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        byte[] inbound = new byte[8192];
+        byte[] outbound = new byte[8192];
+
+        while (!isEngineClosed(serverEngine)) {
+            int len = 0;
+
+            // Inbound data
+            log("================");
+
+            // Read from the Client side.
+            try {
+                len = is.read(inbound);
+                if (len == -1) {
+                    throw new Exception("Unexpected EOF");
+                }
+                cTOs.put(inbound, 0, len);
+            } catch (SocketTimeoutException ste) {
+                // swallow.  Nothing yet, probably waiting on us.
+                System.out.println("Warning: " + ste);
+            }
+
+            cTOs.flip();
+
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            log("server unwrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+            cTOs.compact();
+
+            // Outbound data
+            log("----");
+
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            sTOc.flip();
+
+            if ((len = sTOc.remaining()) != 0) {
+                sTOc.get(outbound, 0, len);
+                os.write(outbound, 0, len);
+                // Give the other side a chance to process
+            }
+
+            sTOc.compact();
+
+            if (!closed && (serverOut.remaining() == 0)) {
+                closed = true;
+
+                /*
+                 * We'll alternate initiatating the shutdown.
+                 * When the server initiates, it will take one more
+                 * loop, but tests the orderly shutdown.
+                 */
+                if (serverClose) {
+                    serverEngine.closeOutbound();
+                }
+            }
+
+            if (closed && isEngineClosed(serverEngine)) {
+                serverIn.flip();
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                if (serverIn.remaining() != clientMsg.length) {
+                    throw new Exception("Client: Data length error -" +
+                        " IF THIS FAILS, PLEASE REPORT THIS TO THE" +
+                        " SECURITY TEAM.  WE HAVE BEEN UNABLE TO" +
+                        " RELIABLY DUPLICATE.");
+                }
+
+                for (int i = 0; i < clientMsg.length; i++) {
+                    if (clientMsg[i] != serverIn.get()) {
+                        throw new Exception("Client: Data content error -" +
+                        " IF THIS FAILS, PLEASE REPORT THIS TO THE" +
+                        " SECURITY TEAM.  WE HAVE BEEN UNABLE TO" +
+                        " RELIABLY DUPLICATE.");
+                    }
+                }
+                serverIn.compact();
+            }
+        }
+    }
+
+    /*
+     * Create a client thread which does simple SSLSocket operations.
+     * We'll write and read one data packet.
+     */
+    private Thread runClient(final boolean serverClose)
+            throws Exception {
+
+        Thread t = new Thread("ClientThread") {
+
+            @Override
+            public void run() {
+                try {
+                    doClientSide(serverClose);
+                } catch (Exception e) {
+                    System.out.println("Client died ...");
+                    e.printStackTrace(System.out);
+                    clientException = e;
+                }
+            }
+        };
+
+        t.start();
+        return t;
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    void doClientSide(boolean serverClose) throws Exception {
+        // Wait for server to get started.
+        //
+        // The server side takes care of the issue if the server cannot
+        // get started in 90 seconds.  The client side would just ignore
+        // the test case if the serer is not ready.
+        boolean serverIsReady =
+                serverCondition.await(90L, TimeUnit.SECONDS);
+        if (!serverIsReady) {
+            System.out.println(
+                    "The server is not ready yet in 90 seconds. " +
+                    "Ignore in client side.");
+            return;
+        }
+
+        SSLSocketFactory sslsf = sslc.getSocketFactory();
+        try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
+            try {
+                sslSocket.connect(
+                        new InetSocketAddress("localhost", serverPort), 15000);
+            } catch (IOException ioe) {
+                // The server side may be impacted by naughty test cases or
+                // third party routines, and cannot accept connections.
+                //
+                // Just ignore the test if the connection cannot be
+                // established.
+                System.out.println(
+                        "Cannot make a connection in 15 seconds. " +
+                        "Ignore in client side.");
+                return;
+            }
+
+            // OK, here the client and server get connected.
+
+            // Signal the server, the client is ready to communicate.
+            clientCondition.countDown();
+
+            // There is still a chance in theory that the server thread may
+            // wait client-ready timeout and then quit.  The chance should
+            // be really rare so we don't consider it until it becomes a
+            // real problem.
+
+            // Run the application in client side.
+            runClientApplication(sslSocket, serverClose);
+        }
+    }
+
+    /*
+     * Define the server side application of the test for the specified socket.
+     */
+    void runClientApplication(SSLSocket sslSocket, boolean serverClose)
+            throws Exception {
+
+        OutputStream os = sslSocket.getOutputStream();
+        InputStream is = sslSocket.getInputStream();
+
+        // write(byte[]) goes in one shot.
+        os.write(clientMsg);
+
+        byte[] inbound = new byte[2048];
+        int pos = 0;
+
+        int len;
+        while ((len = is.read(inbound, pos, 2048 - pos)) != -1) {
+            pos += len;
+            // Let the client do the closing.
+            if ((pos == serverMsg.length) && !serverClose) {
+                sslSocket.close();
+                break;
+            }
+        }
+
+        if (pos != serverMsg.length) {
+            throw new Exception("Client:  Data length error");
+        }
+
+        for (int i = 0; i < serverMsg.length; i++) {
+            if (inbound[i] != serverMsg[i]) {
+                throw new Exception("Client:  Data content error");
+            }
+        }
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngine() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.getNeedClientAuth();
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers(boolean direct) {
+
+        SSLSession session = serverEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        if (direct) {
+            serverIn = ByteBuffer.allocateDirect(appBufferMax + 50);
+            cTOs = ByteBuffer.allocateDirect(netBufferMax);
+            sTOc = ByteBuffer.allocateDirect(netBufferMax);
+        } else {
+            serverIn = ByteBuffer.allocate(appBufferMax + 50);
+            cTOs = ByteBuffer.allocate(netBufferMax);
+            sTOc = ByteBuffer.allocate(netBufferMax);
+        }
+
+        serverOut = ByteBuffer.wrap(serverMsg);
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("\trunning delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                        "handshake shouldn't need additional tasks");
+            }
+            log("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n"
+                    + "\t\"getStatus() / getHandshakeStatus()\" +\n"
+                    + "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str
+                + result.getStatus() + "/" + hsStatus + ", "
+                + result.bytesConsumed() + "/" + result.bytesProduced()
+                + " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/SSLEngineDeadlock.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 2007, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 6492872
+ * @summary Deadlock in SSLEngine
+ * @run main/othervm SSLEngineDeadlock
+ * @author Brad R. Wetmore
+ */
+
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+import java.lang.management.*;
+
+public class SSLEngineDeadlock {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static boolean logging = false;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static boolean debug = false;
+
+    private SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    private volatile boolean testDone = false;
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static String pathToStores = "../../../../javax/net/ssl/etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        // Turn off logging, and only output the test iteration to keep
+        // the noise down.
+        for (int i = 1; i <= 200; i++) {
+            if ((i % 5) == 0) {
+                System.out.println("Test #: " + i);
+            }
+            SSLEngineDeadlock test = new SSLEngineDeadlock();
+            test.runTest();
+
+            detectDeadLock();
+        }
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLEngineDeadlock() throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Create a thread which simply spins on tasks.  This will hopefully
+     * trigger a deadlock between the wrap/unwrap and the tasks.  On our
+     * slow, single-CPU build machine (sol8), it was very repeatable.
+     */
+    private void doTask() {
+        Runnable task;
+
+        while (!testDone) {
+            if ((task = clientEngine.getDelegatedTask()) != null) {
+                task.run();
+            }
+            if ((task = serverEngine.getDelegatedTask()) != null) {
+                task.run();
+            }
+        }
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        SSLEngineResult clientResult;   // results from client's last operation
+        SSLEngineResult serverResult;   // results from server's last operation
+
+        new Thread("SSLEngine Task Dispatcher") {
+            public void run() {
+                try {
+                    doTask();
+                } catch (Exception e) {
+                    System.err.println("Task thread died...test will hang");
+                }
+            }
+        }.start();
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        while (!isEngineClosed(clientEngine) ||
+                !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            log("client wrap: ", clientResult);
+
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            log("server wrap: ", serverResult);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("----");
+
+            clientResult = clientEngine.unwrap(sTOc, clientIn);
+            log("client unwrap: ", clientResult);
+
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            log("server unwrap: ", serverResult);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                log("\tClosing clientEngine's *OUTBOUND*...");
+                clientEngine.closeOutbound();
+                serverEngine.closeOutbound();
+                dataDone = true;
+            }
+        }
+        testDone = true;
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(true);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Detect dead lock
+     */
+    private static void detectDeadLock() throws Exception {
+        ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
+        long[] threadIds = threadBean.findDeadlockedThreads();
+        if (threadIds != null && threadIds.length != 0) {
+            for (long id : threadIds) {
+                ThreadInfo info =
+                    threadBean.getThreadInfo(id, Integer.MAX_VALUE);
+                System.out.println("Deadlocked ThreadInfo: " + info);
+            }
+            throw new Exception("Found Deadlock!");
+        }
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+            result.getStatus() + "/" + hsStatus + ", " +
+            result.bytesConsumed() + "/" + result.bytesProduced() +
+            " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/SSLEngineFailedALPN.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2003, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8207317
+ * @summary SSLEngine negotiation fail Exception behavior changed from
+ *          fail-fast to fail-lazy
+ * @run main/othervm SSLEngineFailedALPN
+ */
+/**
+ * A SSLEngine usage example which simplifies the presentation
+ * by removing the I/O and multi-threading concerns.
+ *
+ * The test creates two SSLEngines, simulating a client and server.
+ * The "transport" layer consists two byte buffers:  think of them
+ * as directly connected pipes.
+ *
+ * Note, this is a *very* simple example: real code will be much more
+ * involved.  For example, different threading and I/O models could be
+ * used, transport mechanisms could close unexpectedly, and so on.
+ *
+ * When this application runs, notice that several messages
+ * (wrap/unwrap) pass before any application data is consumed or
+ * produced.  (For more information, please see the SSL/TLS
+ * specifications.)  There may several steps for a successful handshake,
+ * so it's typical to see the following series of operations:
+ *
+ *      client          server          message
+ *      ======          ======          =======
+ *      wrap()          ...             ClientHello
+ *      ...             unwrap()        ClientHello
+ *      ...             wrap()          ServerHello/Certificate
+ *      unwrap()        ...             ServerHello/Certificate
+ *      wrap()          ...             ClientKeyExchange
+ *      wrap()          ...             ChangeCipherSpec
+ *      wrap()          ...             Finished
+ *      ...             unwrap()        ClientKeyExchange
+ *      ...             unwrap()        ChangeCipherSpec
+ *      ...             unwrap()        Finished
+ *      ...             wrap()          ChangeCipherSpec
+ *      ...             wrap()          Finished
+ *      unwrap()        ...             ChangeCipherSpec
+ *      unwrap()        ...             Finished
+ */
+import javax.net.ssl.*;
+import javax.net.ssl.SSLEngineResult.*;
+import java.io.*;
+import java.security.*;
+import java.nio.*;
+
+public class SSLEngineFailedALPN {
+
+    /*
+     * Enables logging of the SSLEngine operations.
+     */
+    private static final boolean logging = true;
+
+    /*
+     * Enables the JSSE system debugging system property:
+     *
+     *     -Djavax.net.debug=all
+     *
+     * This gives a lot of low-level information about operations underway,
+     * including specific handshake messages, and might be best examined
+     * after gaining some familiarity with this application.
+     */
+    private static final boolean debug = false;
+
+    private final SSLContext sslc;
+
+    private SSLEngine clientEngine;     // client Engine
+    private ByteBuffer clientOut;       // write side of clientEngine
+    private ByteBuffer clientIn;        // read side of clientEngine
+
+    private SSLEngine serverEngine;     // server Engine
+    private ByteBuffer serverOut;       // write side of serverEngine
+    private ByteBuffer serverIn;        // read side of serverEngine
+
+    /*
+     * For data transport, this example uses local ByteBuffers.  This
+     * isn't really useful, but the purpose of this example is to show
+     * SSLEngine concepts, not how to do network transport.
+     */
+    private ByteBuffer cTOs;            // "reliable" transport client->server
+    private ByteBuffer sTOc;            // "reliable" transport server->client
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static final String pathToStores = "../../../../javax/net/ssl/etc";
+    private static final String keyStoreFile = "keystore";
+    private static final String trustStoreFile = "truststore";
+    private static final char[] passphrase = "passphrase".toCharArray();
+
+    private static final String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static final String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+    /*
+     * Main entry point for this test.
+     */
+    public static void main(String args[]) throws Exception {
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        SSLEngineFailedALPN test = new SSLEngineFailedALPN();
+        test.runTest();
+
+        System.out.println("Test Passed.");
+    }
+
+    /*
+     * Create an initialized SSLContext to use for these tests.
+     */
+    public SSLEngineFailedALPN() throws Exception {
+
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("TLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        sslc = sslCtx;
+    }
+
+    /*
+     * Run the test.
+     *
+     * Sit in a tight loop, both engines calling wrap/unwrap regardless
+     * of whether data is available or not.  We do this until both engines
+     * report back they are closed.
+     *
+     * The main loop handles all of the I/O phases of the SSLEngine's
+     * lifetime:
+     *
+     *     initial handshaking
+     *     application data transfer
+     *     engine closing
+     *
+     * One could easily separate these phases into separate
+     * sections of code.
+     */
+    private void runTest() throws Exception {
+        boolean dataDone = false;
+
+        createSSLEngines();
+        createBuffers();
+
+        // results from client's last operation
+        SSLEngineResult clientResult;
+
+        // results from server's last operation
+        SSLEngineResult serverResult;
+
+        /*
+         * Examining the SSLEngineResults could be much more involved,
+         * and may alter the overall flow of the application.
+         *
+         * For example, if we received a BUFFER_OVERFLOW when trying
+         * to write to the output pipe, we could reallocate a larger
+         * pipe, but instead we wait for the peer to drain it.
+         */
+        Exception clientException = null;
+        Exception serverException = null;
+
+        while (!isEngineClosed(clientEngine)
+                || !isEngineClosed(serverEngine)) {
+
+            log("================");
+
+            try {
+                clientResult = clientEngine.wrap(clientOut, cTOs);
+                log("client wrap: ", clientResult);
+            } catch (Exception e) {
+                clientException = e;
+                System.out.println("Client wrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(clientEngine);
+            runDelegatedTasks(clientEngine);
+
+            log("----");
+
+            try {
+                serverResult = serverEngine.wrap(serverOut, sTOc);
+                log("server wrap: ", serverResult);
+            } catch (Exception e) {
+                serverException = e;
+                System.out.println("Server wrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(serverEngine);
+            runDelegatedTasks(serverEngine);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            log("--------");
+
+            try {
+                clientResult = clientEngine.unwrap(sTOc, clientIn);
+                log("client unwrap: ", clientResult);
+            } catch (Exception e) {
+                clientException = e;
+                System.out.println("Client unwrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(clientEngine);
+            runDelegatedTasks(clientEngine);
+
+            log("----");
+
+            try {
+                serverResult = serverEngine.unwrap(cTOs, serverIn);
+                log("server unwrap: ", serverResult);
+            } catch (Exception e) {
+                serverException = e;
+                System.out.println("Server unwrap() threw: " + e.getMessage());
+            }
+            logEngineStatus(serverEngine);
+            runDelegatedTasks(serverEngine);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            /*
+             * After we've transfered all application data between the client
+             * and server, we close the clientEngine's outbound stream.
+             * This generates a close_notify handshake message, which the
+             * server engine receives and responds by closing itself.
+             */
+            if (!dataDone && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                /*
+                 * A sanity check to ensure we got what was sent.
+                 */
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+
+                log("\tClosing clientEngine's *OUTBOUND*...");
+                clientEngine.closeOutbound();
+                logEngineStatus(clientEngine);
+
+                dataDone = true;
+                log("\tClosing serverEngine's *OUTBOUND*...");
+                serverEngine.closeOutbound();
+                logEngineStatus(serverEngine);
+            }
+        }
+
+        log("================");
+
+        if ((clientException != null) &&
+                (clientException instanceof SSLHandshakeException)) {
+            log("Client threw proper exception");
+            clientException.printStackTrace(System.out);
+        } else {
+            throw new Exception("Client Exception not seen");
+        }
+
+        if ((serverException != null) &&
+                (serverException instanceof SSLHandshakeException)) {
+            log("Server threw proper exception:");
+            serverException.printStackTrace(System.out);
+        } else {
+            throw new Exception("Server Exception not seen");
+        }
+    }
+
+    private static void logEngineStatus(SSLEngine engine) {
+        log("\tCurrent HS State  " + engine.getHandshakeStatus().toString());
+        log("\tisInboundDone():  " + engine.isInboundDone());
+        log("\tisOutboundDone(): " + engine.isOutboundDone());
+    }
+
+    /*
+     * Using the SSLContext created during object creation,
+     * create/configure the SSLEngines we'll use for this test.
+     */
+    private void createSSLEngines() throws Exception {
+        /*
+         * Configure the serverEngine to act as a server in the SSL/TLS
+         * handshake.  Also, require SSL client authentication.
+         */
+        serverEngine = sslc.createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(true);
+
+        // Get/set parameters if needed
+        SSLParameters paramsServer = serverEngine.getSSLParameters();
+        paramsServer.setApplicationProtocols(new String[]{"one"});
+        serverEngine.setSSLParameters(paramsServer);
+
+        /*
+         * Similar to above, but using client mode instead.
+         */
+        clientEngine = sslc.createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+
+        // Get/set parameters if needed
+        SSLParameters paramsClient = clientEngine.getSSLParameters();
+        paramsClient.setApplicationProtocols(new String[]{"two"});
+        clientEngine.setSSLParameters(paramsClient);
+    }
+
+    /*
+     * Create and size the buffers appropriately.
+     */
+    private void createBuffers() {
+
+        /*
+         * We'll assume the buffer sizes are the same
+         * between client and server.
+         */
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        /*
+         * We'll make the input buffers a bit bigger than the max needed
+         * size, so that unwrap()s following a successful data transfer
+         * won't generate BUFFER_OVERFLOWS.
+         *
+         * We'll use a mix of direct and indirect ByteBuffers for
+         * tutorial purposes only.  In reality, only use direct
+         * ByteBuffers when they give a clear performance enhancement.
+         */
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+        serverOut = ByteBuffer.wrap("Hello Client, I'm Server".getBytes());
+    }
+
+    /*
+     * If the result indicates that we have outstanding tasks to do,
+     * go ahead and run them in this thread.
+     */
+    private static void runDelegatedTasks(SSLEngine engine) throws Exception {
+
+        if (engine.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                log("    running delegated task...");
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            logEngineStatus(engine);
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    /*
+     * Simple check to make sure everything came across as expected.
+     */
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            log("\tData transferred cleanly");
+        }
+
+        a.position(a.limit());
+        b.position(b.limit());
+        a.limit(a.capacity());
+        b.limit(b.capacity());
+    }
+
+    /*
+     * Logging code
+     */
+    private static boolean resultOnce = true;
+
+    private static void log(String str, SSLEngineResult result) {
+        if (!logging) {
+            return;
+        }
+        if (resultOnce) {
+            resultOnce = false;
+            System.out.println("The format of the SSLEngineResult is: \n" +
+                    "\t\"getStatus() / getHandshakeStatus()\" +\n" +
+                    "\t\"bytesConsumed() / bytesProduced()\"\n");
+        }
+        HandshakeStatus hsStatus = result.getHandshakeStatus();
+        log(str +
+                result.getStatus() + "/" + hsStatus + ", " +
+                result.bytesConsumed() + "/" + result.bytesProduced() +
+                " bytes");
+        if (hsStatus == HandshakeStatus.FINISHED) {
+            log("\t...ready for application data");
+        }
+    }
+
+    private static void log(String str) {
+        if (logging) {
+            System.out.println(str);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/SSLEngineKeyLimit.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8164879
+ * @library /lib/testlibrary ../../
+ * @summary Verify AES/GCM's limits set in the jdk.tls.keyLimits property
+ * start a new handshake sequence to renegotiate the symmetric key with an
+ * SSLSocket connection.  This test verifies the handshake method was called
+ * via debugging info.  It does not verify the renegotiation was successful
+ * as that is very hard.
+ *
+ * @run main SSLEngineKeyLimit 0 server AES/GCM/NoPadding keyupdate 1050000
+ * @run main SSLEngineKeyLimit 1 client AES/GCM/NoPadding keyupdate 2^22
+ */
+
+/*
+ * This test runs in another process so we can monitor the debug
+ * results.  The OutputAnalyzer must see correct debug output to return a
+ * success.
+ */
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
+import java.io.PrintWriter;
+import java.nio.ByteBuffer;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Utils;
+import jdk.testlibrary.OutputAnalyzer;
+
+public class SSLEngineKeyLimit {
+
+    SSLEngine eng;
+    static ByteBuffer cTos;
+    static ByteBuffer sToc;
+    static ByteBuffer outdata;
+    ByteBuffer buf;
+    static boolean ready = false;
+
+    static String pathToStores = "../../../../javax/net/ssl/etc/";
+    static String keyStoreFile = "keystore";
+    static String passwd = "passphrase";
+    static String keyFilename;
+    static int dataLen = 10240;
+    static boolean serverwrite = true;
+    int totalDataLen = 0;
+    static boolean sc = true;
+    int delay = 1;
+    static boolean readdone = false;
+
+    // Turn on debugging
+    static boolean debug = false;
+
+    SSLEngineKeyLimit() {
+        buf = ByteBuffer.allocate(dataLen*4);
+    }
+
+    /**
+     * args should have two values:  server|client, <limit size>
+     * Prepending 'p' is for internal use only.
+     */
+    public static void main(String args[]) throws Exception {
+
+        for (int i = 0; i < args.length; i++) {
+            System.out.print(" " + args[i]);
+        }
+        System.out.println();
+        if (args[0].compareTo("p") != 0) {
+            boolean expectedFail = (Integer.parseInt(args[0]) == 1);
+            if (expectedFail) {
+                System.out.println("Test expected to not find updated msg");
+            }
+
+            // Write security property file to overwrite default
+            File f = new File("keyusage."+ System.nanoTime());
+            PrintWriter p = new PrintWriter(f);
+            p.write("jdk.tls.keyLimits=");
+            for (int i = 2; i < args.length; i++) {
+                p.write(" "+ args[i]);
+            }
+            p.close();
+
+            System.setProperty("test.java.opts",
+                    "-Dtest.src=" + System.getProperty("test.src") +
+                            " -Dtest.jdk=" + System.getProperty("test.jdk") +
+                            " -Djavax.net.debug=ssl,handshake" +
+                            " -Djava.security.properties=" + f.getName());
+
+            System.out.println("test.java.opts: " +
+                    System.getProperty("test.java.opts"));
+
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+                    Utils.addTestJavaOpts("SSLEngineKeyLimit", "p", args[1]));
+
+            OutputAnalyzer output = ProcessTools.executeProcess(pb);
+            try {
+                if (expectedFail) {
+                    output.shouldNotContain("KeyUpdate: write key updated");
+                    output.shouldNotContain("KeyUpdate: read key updated");
+                } else {
+                    output.shouldContain("trigger key update");
+                    output.shouldContain("KeyUpdate: write key updated");
+                    output.shouldContain("KeyUpdate: read key updated");
+                }
+            } catch (Exception e) {
+                throw e;
+            } finally {
+                System.out.println("-- BEGIN Stdout:");
+                System.out.println(output.getStdout());
+                System.out.println("-- END Stdout");
+                System.out.println("-- BEGIN Stderr:");
+                System.out.println(output.getStderr());
+                System.out.println("-- END Stderr");
+            }
+            return;
+        }
+
+        if (args[0].compareTo("p") != 0) {
+            throw new Exception ("Tried to run outside of a spawned process");
+        }
+
+        if (args[1].compareTo("client") == 0) {
+            serverwrite = false;
+        }
+
+        cTos = ByteBuffer.allocateDirect(dataLen*4);
+        keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+
+        sToc = ByteBuffer.allocateDirect(dataLen*4);
+        outdata = ByteBuffer.allocateDirect(dataLen);
+
+        byte[] data  = new byte[dataLen];
+        Arrays.fill(data, (byte)0x0A);
+        outdata.put(data);
+        outdata.flip();
+        cTos.clear();
+        sToc.clear();
+
+        Thread ts = new Thread(serverwrite ? new Client() : new Server());
+        ts.start();
+        (serverwrite ? new Server() : new Client()).run();
+        ts.interrupt();
+        ts.join();
+    }
+
+    private static void doTask(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() ==
+                SSLEngineResult.HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                print("\trunning delegated task...");
+                runnable.run();
+            }
+            SSLEngineResult.HandshakeStatus hsStatus =
+                    engine.getHandshakeStatus();
+            if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+            print("\tnew HandshakeStatus: " + hsStatus);
+        }
+    }
+
+    static void print(String s) {
+        if (debug) {
+            System.out.println(s);
+        }
+    }
+
+    static void log(String s, SSLEngineResult r) {
+        if (!debug) {
+            return;
+        }
+        System.out.println(s + ": " +
+                r.getStatus() + "/" + r.getHandshakeStatus()+ " " +
+                r.bytesConsumed() + "/" + r.bytesProduced() + " ");
+
+    }
+
+    void write() throws Exception {
+        int i = 0;
+        SSLEngineResult r;
+        boolean again = true;
+
+        while (!ready) {
+            Thread.sleep(delay);
+        }
+        print("Write-side. ");
+
+        while (i++ < 150) {
+            while (sc) {
+                if (readdone) {
+                    return;
+                }
+                Thread.sleep(delay);
+            }
+
+            outdata.rewind();
+            print("write wrap");
+
+            while (true) {
+                r = eng.wrap(outdata, getWriteBuf());
+                log("write wrap", r);
+                if (debug && r.getStatus() != SSLEngineResult.Status.OK) {
+                    print("outdata pos: " + outdata.position() +
+                            " rem: " + outdata.remaining() +
+                            " lim: " + outdata.limit() +
+                            " cap: " + outdata.capacity());
+                    print("writebuf pos: " + getWriteBuf().position() +
+                            " rem: " + getWriteBuf().remaining() +
+                            " lim: " + getWriteBuf().limit() +
+                            " cap: " + getWriteBuf().capacity());
+                }
+                if (again && r.getStatus() == SSLEngineResult.Status.OK &&
+                        r.getHandshakeStatus() ==
+                                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+                    print("again");
+                    again = false;
+                    continue;
+                }
+                break;
+            }
+            doTask(r, eng);
+            getWriteBuf().flip();
+            sc = true;
+            while (sc) {
+                if (readdone) {
+                    return;
+                }
+                Thread.sleep(delay);
+            }
+
+            while (true) {
+                buf.clear();
+                r = eng.unwrap(getReadBuf(), buf);
+                log("write unwrap", r);
+                if (debug && r.getStatus() != SSLEngineResult.Status.OK) {
+                    print("buf pos: " + buf.position() +
+                            " rem: " + buf.remaining() +
+                            " lim: " + buf.limit() +
+                            " cap: " + buf.capacity());
+                    print("readbuf pos: " + getReadBuf().position() +
+                            " rem: " + getReadBuf().remaining() +
+                            " lim: " + getReadBuf().limit() +
+                            " cap:"  + getReadBuf().capacity());
+                }
+                break;
+            }
+            doTask(r, eng);
+            getReadBuf().compact();
+            print("compacted readbuf pos: " + getReadBuf().position() +
+                    " rem: " + getReadBuf().remaining() +
+                    " lim: " + getReadBuf().limit() +
+                    " cap: " + getReadBuf().capacity());
+            sc = true;
+        }
+    }
+
+    void read() throws Exception {
+        byte b = 0x0B;
+        ByteBuffer buf2 = ByteBuffer.allocateDirect(dataLen);
+        SSLEngineResult r = null;
+        boolean exit, again = true;
+
+        while (eng == null) {
+            Thread.sleep(delay);
+        }
+
+        try {
+            System.out.println("connected");
+            print("entering read loop");
+            ready = true;
+            while (true) {
+
+                while (!sc) {
+                    Thread.sleep(delay);
+                }
+
+                print("read wrap");
+                exit = false;
+                while (!exit) {
+                    buf2.put(b);
+                    buf2.flip();
+                    r = eng.wrap(buf2, getWriteBuf());
+                    log("read wrap", r);
+                    if (debug) {
+                             // && r.getStatus() != SSLEngineResult.Status.OK) {
+                        print("buf2 pos: " + buf2.position() +
+                                " rem: " + buf2.remaining() +
+                                " cap: " + buf2.capacity());
+                        print("writebuf pos: " + getWriteBuf().position() +
+                                " rem: " + getWriteBuf().remaining() +
+                                " cap: " + getWriteBuf().capacity());
+                    }
+                    if (again && r.getStatus() == SSLEngineResult.Status.OK &&
+                            r.getHandshakeStatus() ==
+                                SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+                        buf2.compact();
+                        again = false;
+                        continue;
+                    }
+                    exit = true;
+                }
+                doTask(r, eng);
+                buf2.clear();
+                getWriteBuf().flip();
+
+                sc = false;
+
+                while (!sc) {
+                    Thread.sleep(delay);
+                }
+
+                while (true) {
+                        buf.clear();
+                        r = eng.unwrap(getReadBuf(), buf);
+                        log("read unwrap", r);
+                        if (debug &&
+                                r.getStatus() != SSLEngineResult.Status.OK) {
+                            print("buf pos " + buf.position() +
+                                    " rem: " + buf.remaining() +
+                                    " lim: " + buf.limit() +
+                                    " cap: " + buf.capacity());
+                            print("readbuf pos: " + getReadBuf().position() +
+                                    " rem: " + getReadBuf().remaining() +
+                                    " lim: " + getReadBuf().limit() +
+                                    " cap: " + getReadBuf().capacity());
+                            doTask(r, eng);
+                        }
+
+                    if (again && r.getStatus() == SSLEngineResult.Status.OK &&
+                            r.getHandshakeStatus() ==
+                                SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
+                        buf.clear();
+                        print("again");
+                        again = false;
+                        continue;
+
+                    }
+                    break;
+                }
+                buf.clear();
+                getReadBuf().compact();
+
+                totalDataLen += r.bytesProduced();
+                sc = false;
+            }
+        } catch (Exception e) {
+            sc = false;
+            readdone = true;
+            System.out.println(e.getMessage());
+            e.printStackTrace();
+            System.out.println("Total data read = " + totalDataLen);
+        }
+    }
+
+    ByteBuffer getReadBuf() {
+        return null;
+    }
+
+    ByteBuffer getWriteBuf() {
+        return null;
+    }
+
+
+    SSLContext initContext() throws Exception {
+        SSLContext sc = SSLContext.getInstance("TLSv1.3");
+        KeyStore ks = KeyStore.getInstance(
+                new File(System.getProperty("javax.net.ssl.keyStore")),
+                passwd.toCharArray());
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
+                KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(ks, passwd.toCharArray());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+                TrustManagerFactory.getDefaultAlgorithm());
+        tmf.init(ks);
+        sc.init(kmf.getKeyManagers(),
+                tmf.getTrustManagers(), new SecureRandom());
+        return sc;
+    }
+
+    static class Server extends SSLEngineKeyLimit implements Runnable {
+        Server() throws Exception {
+            super();
+            eng = initContext().createSSLEngine();
+            eng.setUseClientMode(false);
+            eng.setNeedClientAuth(true);
+        }
+
+        public void run() {
+            try {
+                if (serverwrite) {
+                    write();
+                } else {
+                    read();
+                }
+
+            } catch (Exception e) {
+                System.out.println("server: " + e.getMessage());
+                e.printStackTrace();
+            }
+            System.out.println("Server closed");
+        }
+
+        @Override
+        ByteBuffer getWriteBuf() {
+            return sToc;
+        }
+        @Override
+        ByteBuffer getReadBuf() {
+            return cTos;
+        }
+    }
+
+
+    static class Client extends SSLEngineKeyLimit implements Runnable {
+        Client() throws Exception {
+            super();
+            eng = initContext().createSSLEngine();
+            eng.setUseClientMode(true);
+        }
+
+        public void run() {
+            try {
+                if (!serverwrite) {
+                    write();
+                } else {
+                    read();
+                }
+            } catch (Exception e) {
+                System.out.println("client: " + e.getMessage());
+                e.printStackTrace();
+            }
+            System.out.println("Client closed");
+        }
+        @Override
+        ByteBuffer getWriteBuf() {
+            return cTos;
+        }
+        @Override
+        ByteBuffer getReadBuf() {
+            return sToc;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLEngineImpl/TLS13BeginHandshake.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary Test SSLEngine.begineHandshake() triggers a KeyUpdate handshake
+ * in TLSv1.3
+ * @run main/othervm TLS13BeginHandshake
+ */
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.File;
+import java.nio.ByteBuffer;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+
+public class TLS13BeginHandshake {
+    static String pathToStores =
+            System.getProperty("test.src") + "/../../../../javax/net/ssl/etc/";
+    static String keyStoreFile = "keystore";
+    static String passwd = "passphrase";
+
+    private SSLEngine serverEngine, clientEngine;
+    SSLEngineResult clientResult, serverResult;
+    private ByteBuffer clientOut, clientIn;
+    private ByteBuffer serverOut, serverIn;
+    private ByteBuffer cTOs,sTOc;
+
+    public static void main(String args[]) throws Exception{
+        new TLS13BeginHandshake().runDemo();
+    }
+
+    private void runDemo() throws Exception {
+        int done = 0;
+
+        createSSLEngines();
+        createBuffers();
+
+        while (!isEngineClosed(clientEngine) || !isEngineClosed(serverEngine)) {
+
+            System.out.println("================");
+            clientResult = clientEngine.wrap(clientOut, cTOs);
+            System.out.println("client wrap: " + clientResult);
+            runDelegatedTasks(clientResult, clientEngine);
+            serverResult = serverEngine.wrap(serverOut, sTOc);
+            System.out.println("server wrap: " + serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            cTOs.flip();
+            sTOc.flip();
+
+            System.out.println("----");
+            clientResult = clientEngine.unwrap(sTOc, clientIn);
+            System.out.println("client unwrap: " + clientResult);
+            if (clientResult.getStatus() == SSLEngineResult.Status.CLOSED) {
+                break;
+            }            runDelegatedTasks(clientResult, clientEngine);
+            serverResult = serverEngine.unwrap(cTOs, serverIn);
+            System.out.println("server unwrap: " + serverResult);
+            runDelegatedTasks(serverResult, serverEngine);
+
+            cTOs.compact();
+            sTOc.compact();
+
+            //System.err.println("so limit="+serverOut.limit()+" so pos="+serverOut.position());
+            //System.out.println("bf ctos limit="+cTOs.limit()+" pos="+cTOs.position()+" cap="+cTOs.capacity());
+            //System.out.println("bf stoc limit="+sTOc.limit()+" pos="+sTOc.position()+" cap="+sTOc.capacity());
+            if (done < 2  && (clientOut.limit() == serverIn.position()) &&
+                    (serverOut.limit() == clientIn.position())) {
+
+                if (done == 0) {
+                    checkTransfer(serverOut, clientIn);
+                    checkTransfer(clientOut, serverIn);
+                    clientEngine.beginHandshake();
+                    done++;
+                    continue;
+                }
+
+                checkTransfer(serverOut, clientIn);
+                checkTransfer(clientOut, serverIn);
+                System.out.println("\tClosing...");
+                clientEngine.closeOutbound();
+                serverEngine.closeOutbound();
+                done++;
+                continue;
+            }
+        }
+    }
+
+    private static boolean isEngineClosed(SSLEngine engine) {
+        if (engine.isInboundDone())
+            System.out.println("inbound closed");
+        if (engine.isOutboundDone())
+            System.out.println("outbound closed");
+        return (engine.isOutboundDone() && engine.isInboundDone());
+    }
+
+    private static void checkTransfer(ByteBuffer a, ByteBuffer b)
+            throws Exception {
+        a.flip();
+        b.flip();
+
+        if (!a.equals(b)) {
+            throw new Exception("Data didn't transfer cleanly");
+        } else {
+            System.out.println("\tData transferred cleanly");
+        }
+
+        a.compact();
+        b.compact();
+
+    }
+    private void createBuffers() {
+        SSLSession session = clientEngine.getSession();
+        int appBufferMax = session.getApplicationBufferSize();
+        int netBufferMax = session.getPacketBufferSize();
+
+        clientIn = ByteBuffer.allocate(appBufferMax + 50);
+        serverIn = ByteBuffer.allocate(appBufferMax + 50);
+
+        cTOs = ByteBuffer.allocateDirect(netBufferMax);
+        sTOc = ByteBuffer.allocateDirect(netBufferMax);
+
+        clientOut = ByteBuffer.wrap("client".getBytes());
+        serverOut = ByteBuffer.wrap("server".getBytes());
+    }
+
+    private void createSSLEngines() throws Exception {
+        serverEngine = initContext().createSSLEngine();
+        serverEngine.setUseClientMode(false);
+        serverEngine.setNeedClientAuth(true);
+
+        clientEngine = initContext().createSSLEngine("client", 80);
+        clientEngine.setUseClientMode(true);
+    }
+
+    private SSLContext initContext() throws Exception {
+        SSLContext sc = SSLContext.getInstance("TLSv1.3");
+        KeyStore ks = KeyStore.getInstance(new File(pathToStores + keyStoreFile),
+                passwd.toCharArray());
+        KeyManagerFactory kmf =
+                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(ks, passwd.toCharArray());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        tmf.init(ks);
+        sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+        return sc;
+    }
+
+    private static void runDelegatedTasks(SSLEngineResult result,
+            SSLEngine engine) throws Exception {
+
+        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+            Runnable runnable;
+            while ((runnable = engine.getDelegatedTask()) != null) {
+                runnable.run();
+            }
+            HandshakeStatus hsStatus = engine.getHandshakeStatus();
+            if (hsStatus == HandshakeStatus.NEED_TASK) {
+                throw new Exception(
+                    "handshake shouldn't need additional tasks");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSessionImpl/ResumeChecksClient.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8206929 8212885
+ * @summary ensure that client only resumes a session if certain properties
+ *    of the session are compatible with the new connection
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.2 ResumeChecksClient BASIC
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksClient BASIC
+ * @run main/othervm ResumeChecksClient BASIC
+ * @run main/othervm ResumeChecksClient VERSION_2_TO_3
+ * @run main/othervm ResumeChecksClient VERSION_3_TO_2
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksClient CIPHER_SUITE
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksClient SIGNATURE_SCHEME
+ *
+ */
+
+import javax.net.*;
+import javax.net.ssl.*;
+import java.io.*;
+import java.security.*;
+import java.net.*;
+import java.util.*;
+
+public class ResumeChecksClient {
+
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    enum TestMode {
+        BASIC,
+        VERSION_2_TO_3,
+        VERSION_3_TO_2,
+        CIPHER_SUITE,
+        SIGNATURE_SCHEME
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        TestMode mode = TestMode.valueOf(args[0]);
+
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        Server server = startServer();
+        server.signal();
+        SSLContext sslContext = SSLContext.getDefault();
+        while (!server.started) {
+            Thread.yield();
+        }
+        SSLSession firstSession = connect(sslContext, server.port, mode, false);
+
+        server.signal();
+        long secondStartTime = System.currentTimeMillis();
+        Thread.sleep(10);
+        SSLSession secondSession = connect(sslContext, server.port, mode, true);
+
+        server.go = false;
+        server.signal();
+
+        switch (mode) {
+        case BASIC:
+            // fail if session is not resumed
+            checkResumedSession(firstSession, secondSession);
+            break;
+        case VERSION_2_TO_3:
+        case VERSION_3_TO_2:
+        case CIPHER_SUITE:
+        case SIGNATURE_SCHEME:
+            // fail if a new session is not created
+            if (secondSession.getCreationTime() <= secondStartTime) {
+                throw new RuntimeException("Existing session was used");
+            }
+            break;
+        default:
+            throw new RuntimeException("unknown mode: " + mode);
+        }
+    }
+
+    private static class NoSig implements AlgorithmConstraints {
+
+        private final String alg;
+
+        NoSig(String alg) {
+            this.alg = alg;
+        }
+
+
+        private boolean test(String a) {
+            return !a.toLowerCase().contains(alg.toLowerCase());
+        }
+
+        @Override
+        public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+            return true;
+        }
+        @Override
+        public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, AlgorithmParameters parameters) {
+
+            return test(algorithm);
+        }
+        @Override
+        public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, Key key, AlgorithmParameters parameters) {
+
+            return test(algorithm);
+        }
+    }
+
+    private static SSLSession connect(SSLContext sslContext, int port,
+        TestMode mode, boolean second) {
+
+        try {
+            SSLSocket sock = (SSLSocket)
+                sslContext.getSocketFactory().createSocket();
+            SSLParameters params = sock.getSSLParameters();
+
+            switch (mode) {
+            case BASIC:
+                // do nothing to ensure resumption works
+                break;
+            case VERSION_2_TO_3:
+                if (second) {
+                    params.setProtocols(new String[] {"TLSv1.3"});
+                } else {
+                    params.setProtocols(new String[] {"TLSv1.2"});
+                }
+                break;
+            case VERSION_3_TO_2:
+                if (second) {
+                    params.setProtocols(new String[] {"TLSv1.2"});
+                } else {
+                    params.setProtocols(new String[] {"TLSv1.3"});
+                }
+                break;
+            case CIPHER_SUITE:
+                if (second) {
+                    params.setCipherSuites(
+                        new String[] {"TLS_AES_256_GCM_SHA384"});
+                } else {
+                    params.setCipherSuites(
+                        new String[] {"TLS_AES_128_GCM_SHA256"});
+                }
+                break;
+            case SIGNATURE_SCHEME:
+                AlgorithmConstraints constraints =
+                    params.getAlgorithmConstraints();
+                if (second) {
+                    params.setAlgorithmConstraints(new NoSig("ecdsa"));
+                } else {
+                    params.setAlgorithmConstraints(new NoSig("rsa"));
+                }
+                break;
+            default:
+                throw new RuntimeException("unknown mode: " + mode);
+            }
+            sock.setSSLParameters(params);
+            sock.connect(new InetSocketAddress("localhost", port));
+            PrintWriter out = new PrintWriter(
+                new OutputStreamWriter(sock.getOutputStream()));
+            out.println("message");
+            out.flush();
+            BufferedReader reader = new BufferedReader(
+                new InputStreamReader(sock.getInputStream()));
+            String inMsg = reader.readLine();
+            System.out.println("Client received: " + inMsg);
+            SSLSession result = sock.getSession();
+            sock.close();
+            return result;
+        } catch (Exception ex) {
+            // unexpected exception
+            throw new RuntimeException(ex);
+        }
+    }
+
+    private static void checkResumedSession(SSLSession initSession,
+            SSLSession resSession) throws Exception {
+        StringBuilder diffLog = new StringBuilder();
+
+        // Initial and resumed SSLSessions should have the same creation
+        // times so they get invalidated together.
+        long initCt = initSession.getCreationTime();
+        long resumeCt = resSession.getCreationTime();
+        if (initCt != resumeCt) {
+            diffLog.append("Session creation time is different. Initial: ").
+                    append(initCt).append(", Resumed: ").append(resumeCt).
+                    append("\n");
+        }
+
+        // Ensure that peer and local certificate lists are preserved
+        if (!Arrays.equals(initSession.getLocalCertificates(),
+                resSession.getLocalCertificates())) {
+            diffLog.append("Local certificate mismatch between initial " +
+                    "and resumed sessions\n");
+        }
+
+        if (!Arrays.equals(initSession.getPeerCertificates(),
+                resSession.getPeerCertificates())) {
+            diffLog.append("Peer certificate mismatch between initial " +
+                    "and resumed sessions\n");
+        }
+
+        // Buffer sizes should also be the same
+        if (initSession.getApplicationBufferSize() !=
+                resSession.getApplicationBufferSize()) {
+            diffLog.append(String.format(
+                    "App Buffer sizes differ: Init: %d, Res: %d\n",
+                    initSession.getApplicationBufferSize(),
+                    resSession.getApplicationBufferSize()));
+        }
+
+        if (initSession.getPacketBufferSize() !=
+                resSession.getPacketBufferSize()) {
+            diffLog.append(String.format(
+                    "Packet Buffer sizes differ: Init: %d, Res: %d\n",
+                    initSession.getPacketBufferSize(),
+                    resSession.getPacketBufferSize()));
+        }
+
+        // Cipher suite should match
+        if (!initSession.getCipherSuite().equals(
+                resSession.getCipherSuite())) {
+            diffLog.append(String.format(
+                    "CipherSuite does not match - Init: %s, Res: %s\n",
+                    initSession.getCipherSuite(), resSession.getCipherSuite()));
+        }
+
+        // Peer host/port should match
+        if (!initSession.getPeerHost().equals(resSession.getPeerHost()) ||
+                initSession.getPeerPort() != resSession.getPeerPort()) {
+            diffLog.append(String.format(
+                    "Host/Port mismatch - Init: %s/%d, Res: %s/%d\n",
+                    initSession.getPeerHost(), initSession.getPeerPort(),
+                    resSession.getPeerHost(), resSession.getPeerPort()));
+        }
+
+        // Check protocol
+        if (!initSession.getProtocol().equals(resSession.getProtocol())) {
+            diffLog.append(String.format(
+                    "Protocol mismatch - Init: %s, Res: %s\n",
+                    initSession.getProtocol(), resSession.getProtocol()));
+        }
+
+        // If the StringBuilder has any data in it then one of the checks
+        // above failed and we should throw an exception.
+        if (diffLog.length() > 0) {
+            throw new RuntimeException(diffLog.toString());
+        }
+    }
+
+    private static Server startServer() {
+        Server server = new Server();
+        new Thread(server).start();
+        return server;
+    }
+
+    private static class Server implements Runnable {
+
+        public volatile boolean go = true;
+        private boolean signal = false;
+        public volatile int port = 0;
+        public volatile boolean started = false;
+
+        private synchronized void waitForSignal() {
+            while (!signal) {
+                try {
+                    wait();
+                } catch (InterruptedException ex) {
+                    // do nothing
+                }
+            }
+            signal = false;
+        }
+        public synchronized void signal() {
+            signal = true;
+            notify();
+        }
+
+        @Override
+        public void run() {
+            try {
+
+                SSLContext sc = SSLContext.getDefault();
+                ServerSocketFactory fac = sc.getServerSocketFactory();
+                SSLServerSocket ssock = (SSLServerSocket)
+                    fac.createServerSocket(0);
+                this.port = ssock.getLocalPort();
+
+                waitForSignal();
+                started = true;
+                while (go) {
+                    try {
+                        System.out.println("Waiting for connection");
+                        Socket sock = ssock.accept();
+                        BufferedReader reader = new BufferedReader(
+                            new InputStreamReader(sock.getInputStream()));
+                        String line = reader.readLine();
+                        System.out.println("server read: " + line);
+                        PrintWriter out = new PrintWriter(
+                            new OutputStreamWriter(sock.getOutputStream()));
+                        out.println(line);
+                        out.flush();
+                        waitForSignal();
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSessionImpl/ResumeChecksServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8206929
+ * @summary ensure that server only resumes a session if certain properties
+ *    of the session are compatible with the new connection
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.2 ResumeChecksServer BASIC
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksServer BASIC
+ * @run main/othervm ResumeChecksServer BASIC
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.2 ResumeChecksServer CLIENT_AUTH
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksServer CLIENT_AUTH
+ * @run main/othervm ResumeChecksServer CLIENT_AUTH
+ * @run main/othervm ResumeChecksServer VERSION_2_TO_3
+ * @run main/othervm ResumeChecksServer VERSION_3_TO_2
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksServer CIPHER_SUITE
+ * @run main/othervm -Djdk.tls.client.protocols=TLSv1.3 ResumeChecksServer SIGNATURE_SCHEME
+ *
+ */
+
+import javax.net.*;
+import javax.net.ssl.*;
+import java.io.*;
+import java.security.*;
+import java.net.*;
+import java.util.*;
+
+public class ResumeChecksServer {
+
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    enum TestMode {
+        BASIC,
+        CLIENT_AUTH,
+        VERSION_2_TO_3,
+        VERSION_3_TO_2,
+        CIPHER_SUITE,
+        SIGNATURE_SCHEME
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        TestMode mode = TestMode.valueOf(args[0]);
+
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        SSLSession secondSession = null;
+
+        SSLContext sslContext = SSLContext.getDefault();
+        ServerSocketFactory fac = sslContext.getServerSocketFactory();
+        SSLServerSocket ssock = (SSLServerSocket)
+            fac.createServerSocket(0);
+
+        Client client = startClient(ssock.getLocalPort());
+
+        try {
+            connect(client, ssock, mode, false);
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+
+        long secondStartTime = System.currentTimeMillis();
+        Thread.sleep(10);
+        try {
+            secondSession = connect(client, ssock, mode, true);
+        } catch (SSLHandshakeException ex) {
+            // this is expected
+        } catch (Exception ex) {
+            throw new RuntimeException(ex);
+        }
+
+        client.go = false;
+        client.signal();
+
+        switch (mode) {
+        case BASIC:
+            // fail if session is not resumed
+            if (secondSession.getCreationTime() > secondStartTime) {
+                throw new RuntimeException("Session was not reused");
+            }
+            break;
+        case CLIENT_AUTH:
+            // throws an exception if the client is not authenticated
+            secondSession.getPeerCertificates();
+            break;
+        case VERSION_2_TO_3:
+        case VERSION_3_TO_2:
+        case CIPHER_SUITE:
+        case SIGNATURE_SCHEME:
+            // fail if a new session is not created
+            if (secondSession.getCreationTime() <= secondStartTime) {
+                throw new RuntimeException("Existing session was used");
+            }
+            break;
+        default:
+            throw new RuntimeException("unknown mode: " + mode);
+        }
+    }
+
+    private static class NoSig implements AlgorithmConstraints {
+
+        private final String alg;
+
+        NoSig(String alg) {
+            this.alg = alg;
+        }
+
+
+        private boolean test(String a) {
+            return !a.toLowerCase().contains(alg.toLowerCase());
+        }
+
+        public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+            return true;
+        }
+        public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, AlgorithmParameters parameters) {
+
+            return test(algorithm);
+        }
+        public boolean permits(Set<CryptoPrimitive> primitives,
+            String algorithm, Key key, AlgorithmParameters parameters) {
+
+            return test(algorithm);
+        }
+    }
+
+    private static SSLSession connect(Client client, SSLServerSocket ssock,
+        TestMode mode, boolean second) throws Exception {
+
+        try {
+            client.signal();
+            System.out.println("Waiting for connection");
+            SSLSocket sock = (SSLSocket) ssock.accept();
+            SSLParameters params = sock.getSSLParameters();
+
+            switch (mode) {
+            case BASIC:
+                // do nothing to ensure resumption works
+                break;
+            case CLIENT_AUTH:
+                if (second) {
+                    params.setNeedClientAuth(true);
+                } else {
+                    params.setNeedClientAuth(false);
+                }
+                break;
+            case VERSION_2_TO_3:
+                if (second) {
+                    params.setProtocols(new String[] {"TLSv1.3"});
+                } else {
+                    params.setProtocols(new String[] {"TLSv1.2"});
+                }
+                break;
+            case VERSION_3_TO_2:
+                if (second) {
+                    params.setProtocols(new String[] {"TLSv1.2"});
+                } else {
+                    params.setProtocols(new String[] {"TLSv1.3"});
+                }
+                break;
+            case CIPHER_SUITE:
+                if (second) {
+                    params.setCipherSuites(
+                        new String[] {"TLS_AES_128_GCM_SHA256"});
+                } else {
+                    params.setCipherSuites(
+                        new String[] {"TLS_AES_256_GCM_SHA384"});
+                }
+                break;
+            case SIGNATURE_SCHEME:
+                params.setNeedClientAuth(true);
+                AlgorithmConstraints constraints =
+                    params.getAlgorithmConstraints();
+                if (second) {
+                    params.setAlgorithmConstraints(new NoSig("ecdsa"));
+                } else {
+                    params.setAlgorithmConstraints(new NoSig("rsa"));
+                }
+                break;
+            default:
+                throw new RuntimeException("unknown mode: " + mode);
+            }
+            sock.setSSLParameters(params);
+            BufferedReader reader = new BufferedReader(
+                new InputStreamReader(sock.getInputStream()));
+            String line = reader.readLine();
+            System.out.println("server read: " + line);
+            PrintWriter out = new PrintWriter(
+                new OutputStreamWriter(sock.getOutputStream()));
+            out.println(line);
+            out.flush();
+            out.close();
+            SSLSession result = sock.getSession();
+            sock.close();
+            return result;
+        } catch (SSLHandshakeException ex) {
+            if (!second) {
+                throw ex;
+            }
+        }
+        return null;
+    }
+
+    private static Client startClient(int port) {
+        Client client = new Client(port);
+        new Thread(client).start();
+        return client;
+    }
+
+    private static class Client implements Runnable {
+
+        public volatile boolean go = true;
+        private boolean signal = false;
+        private final int port;
+
+        Client(int port) {
+            this.port = port;
+        }
+
+        private synchronized void waitForSignal() {
+            while (!signal) {
+                try {
+                    wait();
+                } catch (InterruptedException ex) {
+                    // do nothing
+                }
+            }
+            signal = false;
+
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException ex) {
+                // do nothing
+            }
+        }
+        public synchronized void signal() {
+            signal = true;
+            notify();
+        }
+
+        public void run() {
+            try {
+
+                SSLContext sc = SSLContext.getDefault();
+
+                waitForSignal();
+                while (go) {
+                    try {
+                        SSLSocket sock = (SSLSocket)
+                            sc.getSocketFactory().createSocket();
+                        sock.connect(new InetSocketAddress("localhost", port));
+                        PrintWriter out = new PrintWriter(
+                            new OutputStreamWriter(sock.getOutputStream()));
+                        out.println("message");
+                        out.flush();
+                        BufferedReader reader = new BufferedReader(
+                            new InputStreamReader(sock.getInputStream()));
+                        String inMsg = reader.readLine();
+                        System.out.println("Client received: " + inMsg);
+                        out.close();
+                        sock.close();
+                        waitForSignal();
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                }
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/AsyncSSLSocketClose.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2007, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 6447412
+ * @summary Issue with socket.close() for ssl sockets when poweroff on
+ *          other system
+ * @run main/othervm AsyncSSLSocketClose
+ */
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.SocketException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class AsyncSSLSocketClose implements Runnable {
+    SSLSocket socket;
+    SSLServerSocket ss;
+
+    // Is the socket ready to close?
+    private final CountDownLatch closeCondition = new CountDownLatch(1);
+
+    // Where do we find the keystores?
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        new AsyncSSLSocketClose();
+    }
+
+    public AsyncSSLSocketClose() throws Exception {
+        SSLServerSocketFactory sslssf =
+                (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+        ss = (SSLServerSocket) sslssf.createServerSocket(0);
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory)SSLSocketFactory.getDefault();
+        socket = (SSLSocket)sslsf.createSocket("localhost", ss.getLocalPort());
+        SSLSocket serverSoc = (SSLSocket)ss.accept();
+        ss.close();
+
+        (new Thread(this)).start();
+        serverSoc.startHandshake();
+
+        boolean closeIsReady = closeCondition.await(90L, TimeUnit.SECONDS);
+        if (!closeIsReady) {
+            System.out.println(
+                    "Ignore, the closure is not ready yet in 90 seconds.");
+            return;
+        }
+
+        socket.setSoLinger(true, 10);
+        System.out.println("Calling Socket.close");
+        socket.close();
+        System.out.println("ssl socket get closed");
+        System.out.flush();
+    }
+
+    // block in write
+    public void run() {
+        byte[] ba = new byte[1024];
+        for (int i = 0; i < ba.length; i++) {
+            ba[i] = 0x7A;
+        }
+
+        try {
+            OutputStream os = socket.getOutputStream();
+            int count = 0;
+
+            // 1st round write
+            count += ba.length;
+            System.out.println(count + " bytes to be written");
+            os.write(ba);
+            System.out.println(count + " bytes written");
+
+            // Signal, ready to close.
+            closeCondition.countDown();
+
+            // write more
+            while (true) {
+                count += ba.length;
+                System.out.println(count + " bytes to be written");
+                os.write(ba);
+                System.out.println(count + " bytes written");
+            }
+        } catch (SocketException se) {
+            // the closing may be in progress
+            System.out.println("interrupted? " + se);
+        } catch (Exception e) {
+            if (socket.isClosed() || socket.isOutputShutdown()) {
+                System.out.println("interrupted, the socket is closed");
+            } else {
+                throw new RuntimeException("interrupted?", e);
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/CheckMethods.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2003, 2007, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4791676
+ * @summary various pass through methods missing in SSLSocketImpl
+ */
+import java.net.*;
+import java.util.*;
+import java.lang.reflect.*;
+
+public class CheckMethods {
+    static boolean debug = false;
+    static class MethodSignature {
+        String name;
+        Class[] paramTypes;
+        MethodSignature(String name, Class[] paramTypes) {
+            this.name = name;
+            this.paramTypes = paramTypes;
+        }
+
+        public boolean equals(Object obj) {
+            if (debug) {
+                System.out.println("comparing " + this + " against: " + obj);
+            }
+            if (!(obj instanceof MethodSignature)) {
+                if (debug)
+                    System.out.println(false);
+                return false;
+            }
+            MethodSignature ms = (MethodSignature) obj;
+            Class[] types = ms.paramTypes;
+            try {
+                for (int i = 0; i < types.length; i++) {
+                    if (!types[i].equals(paramTypes[i])) {
+                        if (debug)
+                            System.out.println(false);
+                        return false;
+                    }
+                }
+            } catch (Exception e) {
+                if (debug)
+                    System.out.println(false);
+                return false;
+            }
+            boolean result = this.name.equals(ms.name);
+            if (debug)
+                System.out.println(result);
+            return result;
+        }
+
+        public String toString() {
+            StringBuffer sb = new StringBuffer(name + "(");
+            for (int i = 0; i < paramTypes.length; i++) {
+                sb.append(paramTypes[i].getName() + ",");
+                if (i == (paramTypes.length - 1))
+                    sb.deleteCharAt(sb.length() - 1);
+            }
+            sb.append(")");
+            return sb.toString();
+        }
+    }
+
+    // check that SSLSocket contains all public and protected
+    // methods defined in Socket
+    public static void main(String[] args) throws Exception {
+        ArrayList allMethods = new ArrayList(
+                Arrays.asList(Socket.class.getDeclaredMethods()));
+
+        ArrayList allMethodSignatures = new ArrayList();
+        for (Iterator itr = allMethods.iterator(); itr.hasNext();) {
+            Method m = (Method) itr.next();
+            // don't include static and private methods
+            if (!Modifier.isStatic(m.getModifiers()) &&
+                    (Modifier.isPublic(m.getModifiers()) ||
+                    Modifier.isProtected(m.getModifiers()))) {
+                allMethodSignatures.add( new MethodSignature(m.getName(),
+                        m.getParameterTypes()));
+            }
+        }
+
+        // testing Socket
+        Class sslSI = Class.forName(
+            "sun.security.ssl.SSLSocketImpl");
+        Class baseSSLSI = Class.forName(
+            "sun.security.ssl.BaseSSLSocketImpl");
+
+        ArrayList sslSocketMethods =
+                new ArrayList(Arrays.asList(sslSI.getDeclaredMethods()));
+
+        sslSocketMethods.addAll( new ArrayList(
+                Arrays.asList(baseSSLSI.getDeclaredMethods())));
+
+        ArrayList sslSocketMethodSignatures = new ArrayList();
+        for (Iterator itr = sslSocketMethods.iterator(); itr.hasNext();) {
+            Method m = (Method) itr.next();
+            if (!Modifier.isStatic(m.getModifiers())) {
+                sslSocketMethodSignatures.add(
+                        new MethodSignature(m.getName(),
+                        m.getParameterTypes()));
+            }
+        }
+
+        if (!sslSocketMethodSignatures.containsAll(allMethodSignatures)) {
+            throw new RuntimeException(
+                "Method definition test failed on SSLSocketImpl");
+        }
+
+        // testing for non static public field
+        ArrayList allFields =
+                new ArrayList(Arrays.asList(Socket.class.getFields()));
+
+        for (Iterator itr = allFields.iterator(); itr.hasNext();) {
+            Field f = (Field) itr.next();
+            if (!Modifier.isStatic(f.getModifiers())) {
+                throw new RuntimeException("Non static Public fields" +
+                        " declared in superclasses");
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/ClientTimeout.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2005, 2011, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 4836493
+ * @ignore need further evaluation
+ * @summary Socket timeouts for SSLSockets causes data corruption.
+ * @run main/othervm ClientTimeout
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.security.*;
+import javax.net.ssl.*;
+
+public class ClientTimeout {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+
+    /*
+     * define the rhythm of timeout exception
+     */
+    static boolean rhythm = true;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+        sslSocket.startHandshake();
+
+        // transfer a file to client.
+        String transFilename =
+            System.getProperty("test.src", "./") + "/" +
+                        this.getClass().getName() + ".java";
+        MessageDigest md = MessageDigest.getInstance("SHA");
+        DigestInputStream transIns = new DigestInputStream(
+                new FileInputStream(transFilename), md);
+
+        byte[] bytes = new byte[2000];
+        int i = 0;
+        while (true) {
+            // reset the cycle
+            if (i >= bytes.length) {
+                i = 0;
+            }
+
+            int length = 0;
+            if ((length = transIns.read(bytes, 0, i++)) == -1) {
+                break;
+            } else {
+                sslOS.write(bytes, 0, length);
+                sslOS.flush();
+
+                if (i % 3 == 0) {
+                    Thread.sleep(300);  // Stall past the timeout...
+                }
+            }
+        }
+        serverDigest = md.digest();
+        transIns.close();
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        boolean caught = false;
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        Socket baseSocket = new Socket("localhost", serverPort) {
+            MyInputStream ins = null;
+
+            public InputStream getInputStream() throws IOException {
+                if (ins != null) {
+                    return ins;
+                } else {
+                    ins = new MyInputStream(super.getInputStream());
+                    return ins;
+                }
+            }
+        };
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket(baseSocket, "localhost", serverPort, true);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        // handshaking
+        sslSocket.setSoTimeout(100); // The stall timeout.
+        while (true) {
+            try {
+                rhythm = true;
+                sslSocket.startHandshake();
+                break;
+            } catch (SocketTimeoutException e) {
+                System.out.println("Handshaker exception: "
+                        + e.getMessage());
+            }
+        }
+
+        // read application data from server
+        MessageDigest md = MessageDigest.getInstance("SHA");
+        DigestInputStream transIns = new DigestInputStream(sslIS, md);
+        byte[] bytes = new byte[2000];
+        while (true) {
+            try {
+                rhythm = true;
+
+                while (transIns.read(bytes, 0, 17) != -1) {
+                    rhythm = true;
+                }
+                break;
+            } catch (SocketTimeoutException e) {
+                System.out.println("InputStream Exception: "
+                        + e.getMessage());
+            }
+        }
+        // Wait for server to get ready.
+        while (serverDigest == null) {
+            Thread.sleep(20);
+        }
+
+        byte[] cliDigest = md.digest();
+        if (!Arrays.equals(cliDigest, serverDigest)) {
+            throw new Exception("Application data trans error");
+        }
+
+        transIns.close();
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    static class MyInputStream extends InputStream {
+        InputStream ins = null;
+
+        public MyInputStream(InputStream ins) {
+            this.ins = ins;
+        }
+
+        public int read() throws IOException {
+            return read(new byte[1], 0, 1);
+        }
+
+        public int read(byte[] data, int offset, int len) throws IOException {
+            if (!ClientTimeout.rhythm) {
+                throw new SocketTimeoutException(
+                        "Throwing a timeout exception");
+            }
+            ClientTimeout.rhythm = false;
+            return ins.read(data, offset, len);
+        }
+    }
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    volatile byte[] serverDigest = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ClientTimeout();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ClientTimeout() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        System.err.println(e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/InvalidateServerSessionRenegotiate.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2001, 2011, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4403428
+ * @summary Invalidating JSSE session on server causes SSLProtocolException
+ * @run main/othervm InvalidateServerSessionRenegotiate SSLv3
+ * @run main/othervm InvalidateServerSessionRenegotiate TLSv1
+ * @run main/othervm InvalidateServerSessionRenegotiate TLSv1.1
+ * @run main/othervm InvalidateServerSessionRenegotiate TLSv1.2
+ * @author Brad Wetmore
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.Security;
+import javax.net.ssl.*;
+
+public class InvalidateServerSessionRenegotiate implements
+        HandshakeCompletedListener {
+
+    static byte handshakesCompleted = 0;
+
+    /*
+     * Define what happens when handshaking is completed
+     */
+    public void handshakeCompleted(HandshakeCompletedEvent event) {
+        synchronized (this) {
+            handshakesCompleted++;
+            System.out.println("Session: " + event.getSession().toString());
+            System.out.println("Seen handshake completed #" +
+                handshakesCompleted);
+        }
+    }
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.addHandshakeCompletedListener(this);
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        System.out.println("invalidating");
+        sslSocket.getSession().invalidate();
+        System.out.println("starting new handshake");
+        sslSocket.startHandshake();
+
+        for (int i = 0; i < 10; i++) {
+            System.out.println("sending/receiving data, iteration: " + i);
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledProtocols(new String[] { tlsProtocol });
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    // the specified protocol
+    private static String tlsProtocol;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        tlsProtocol = args[0];
+
+        /*
+         * Start the tests.
+         */
+        new InvalidateServerSessionRenegotiate();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    InvalidateServerSessionRenegotiate() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+
+        /*
+         * Give the Handshaker Thread a chance to run
+         */
+        Thread.sleep(1000);
+
+        synchronized (this) {
+            if (handshakesCompleted != 2) {
+                throw new Exception("Didn't see 2 handshake completed events.");
+            }
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/LargePacketAfterHandshakeTest.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+/*
+ * @test
+ * @bug 8149169
+ * @summary Test for BufferOverflowException during read from SSLSocket when
+ *          large packet is coming from server after server initiated handshake
+ * @run main/othervm LargePacketAfterHandshakeTest
+ */
+public class LargePacketAfterHandshakeTest {
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    volatile static int serverport = -1;
+    volatile static boolean serverReady = false;
+    volatile static boolean clientDone = false;
+    volatile static Exception serverException = null;
+
+    public static void runServer() {
+        try {
+            System.out.println("Server: Started server thread.");
+            SSLServerSocketFactory ssf =
+                (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+            SSLServerSocket s = (SSLServerSocket)ssf.createServerSocket(0);
+            serverport = s.getLocalPort();
+            System.out.println("Server: Started, listening on port " +
+                    serverport + ".");
+            serverReady = true;
+            SSLSocket c = (SSLSocket)s.accept();
+            s.close();
+            System.out.println(
+                "Server: Accepted client connection and closed server socket.");
+            BufferedReader r = new BufferedReader(
+                    new InputStreamReader(c.getInputStream()));
+            BufferedWriter w = new BufferedWriter(
+                    new OutputStreamWriter(c.getOutputStream()));
+            String echostring = r.readLine();
+            System.out.println("Server: Read " + echostring.length() +
+                    " chars of input data.");
+            c.startHandshake();
+            System.out.println("Server: Kicked new handshake.");
+            w.write(echostring);
+            w.newLine();
+            w.flush();
+            System.out.println("Server: Echoed " + echostring.length() +
+                    " chars of input data.");
+            while (!clientDone) {
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    System.out.println("Server: Caught InterruptedException.");
+                }
+            }
+            r.close();
+            w.close();
+            c.close();
+            System.out.println(
+                    "Server: Closed streams and client socket, exiting.");
+        } catch (Exception e) {
+            System.out.println("Server: Caught Exception.");
+            e.printStackTrace();
+            serverReady = true;
+            serverException = e;
+        }
+    }
+
+    public static void runClient() throws IOException {
+        try {
+            SSLSocketFactory f =
+                    (SSLSocketFactory)SSLSocketFactory.getDefault();
+            System.out.println("Client: Initialized.");
+            while (!serverReady) {
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    System.out.println("Client: Caught InterruptedException.");
+                }
+            }
+            SSLSocket c = (SSLSocket)f.createSocket("localhost", serverport);
+            BufferedWriter w = new BufferedWriter(
+                    new OutputStreamWriter(c.getOutputStream()));
+            BufferedReader r = new BufferedReader(
+                    new InputStreamReader(c.getInputStream()));
+            System.out.println("Client: Connected.");
+            String echoPattern = "Otto";
+            StringBuilder echoBuilder =
+                    new StringBuilder(4500 + echoPattern.length());
+            while (echoBuilder.length() < 4500) {
+                echoBuilder.append(echoPattern);
+            }
+            String echostring = echoBuilder.toString();
+            w.write(echostring);
+            w.newLine();
+            w.flush();
+            System.out.println("Client: Sent " + echostring.length() +
+                    " chars of data.");
+            String echoresponse = r.readLine();
+            clientDone = true;
+            System.out.println("Client: Read " + echoresponse.length() +
+                    " chars of data.");
+            w.close();
+            r.close();
+            c.close();
+            System.out.println("Client: Closed streams and socket, exiting.");
+        } catch (IOException e) {
+            System.out.println("Client: Caught Exception.");
+            e.printStackTrace();
+            clientDone = true;
+            throw e;
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename = System.getProperty("test.src", "./") + "/" +
+                pathToStores + "/" + keyStoreFile;
+        String trustFilename = System.getProperty("test.src", "./") + "/" +
+                pathToStores + "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        Thread serverThread = new Thread() {
+            @Override
+            public void run() {
+                runServer();
+            }
+        };
+        serverThread.start();
+        runClient();
+        while (serverThread.isAlive()) {
+            try {
+                serverThread.join();
+            } catch (InterruptedException e) {
+                System.out.println("Main: Caught InterruptedException " +
+                        " waiting for server Thread.");
+            }
+        }
+        if (serverException != null) {
+            throw serverException;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/NoImpactServerRenego.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7188658
+ * @summary Add possibility to disable client initiated renegotiation
+ * @run main/othervm  -Djdk.tls.rejectClientInitiatedRenegotiation=true
+ *      NoImpactServerRenego SSLv3
+ * @run main/othervm  -Djdk.tls.rejectClientInitiatedRenegotiation=true
+ *      NoImpactServerRenego TLSv1
+ * @run main/othervm  -Djdk.tls.rejectClientInitiatedRenegotiation=true
+ *      NoImpactServerRenego TLSv1.1
+ * @run main/othervm  -Djdk.tls.rejectClientInitiatedRenegotiation=true
+ *      NoImpactServerRenego TLSv1.2
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.Security;
+import javax.net.ssl.*;
+
+public class NoImpactServerRenego implements
+        HandshakeCompletedListener {
+
+    static byte handshakesCompleted = 0;
+
+    /*
+     * Define what happens when handshaking is completed
+     */
+    public void handshakeCompleted(HandshakeCompletedEvent event) {
+        synchronized (this) {
+            handshakesCompleted++;
+            System.out.println("Session: " + event.getSession().toString());
+            System.out.println("Seen handshake completed #" +
+                handshakesCompleted);
+        }
+    }
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.addHandshakeCompletedListener(this);
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        System.out.println("invalidating");
+        sslSocket.getSession().invalidate();
+        System.out.println("starting new handshake");
+        sslSocket.startHandshake();
+
+        for (int i = 0; i < 10; i++) {
+            System.out.println("sending/receiving data, iteration: " + i);
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledProtocols(new String[] { tlsProtocol });
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    // the specified protocol
+    private static String tlsProtocol;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        tlsProtocol = args[0];
+
+        /*
+         * Start the tests.
+         */
+        new NoImpactServerRenego();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    NoImpactServerRenego() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+
+        /*
+         * Give the Handshaker Thread a chance to run
+         */
+        Thread.sleep(1000);
+
+        synchronized (this) {
+            if (handshakesCompleted != 2) {
+                throw new Exception("Didn't see 2 handshake completed events.");
+            }
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/NonAutoClose.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2001, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4404399
+ * @ignore this test does not work any more as the TLS spec changes the
+ *         behaviors of close_notify.
+ * @summary When a layered SSL socket is closed, it should wait for close_notify
+ * @run main/othervm NonAutoClose
+ * @author Brad Wetmore
+ */
+
+import java.io.*;
+import java.net.ServerSocket;
+import java.net.Socket;
+import javax.net.ssl.*;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+
+
+public class NonAutoClose {
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    private static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    private final static String pathToStores = "../../../../javax/net/ssl/etc";
+    private final static String keyStoreFile = "keystore";
+    private final static String trustStoreFile = "truststore";
+    private final static String passwd = "passphrase";
+    private final static char[] cpasswd = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    private final static boolean DEBUG = false;
+    private final static boolean VERBOSE = true;
+    private final static int NUM_ITERATIONS  = 10;
+    private final static int PLAIN_SERVER_VAL = 1;
+    private final static int PLAIN_CLIENT_VAL = 2;
+    private final static int TLS_SERVER_VAL = 3;
+    private final static int TLS_CLIENT_VAL = 4;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    void expectValue(int got, int expected, String msg) throws IOException {
+        if (VERBOSE) {
+            System.err.println(msg + ": read (" + got + ")");
+        }
+        if (got != expected) {
+            throw new IOException(msg + ": read (" + got
+                + ") but expecting(" + expected + ")");
+        }
+    }
+
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+
+     void doServerSide() throws Exception {
+        if (VERBOSE) {
+            System.err.println("Starting server");
+        }
+
+        /*
+         * Setup the SSL stuff
+         */
+        SSLSocketFactory sslsf =
+             (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        ServerSocket serverSocket = new ServerSocket(SERVER_PORT);
+
+        SERVER_PORT = serverSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        Socket plainSocket = serverSocket.accept();
+        InputStream is = plainSocket.getInputStream();
+        OutputStream os = plainSocket.getOutputStream();
+
+        expectValue(is.read(), PLAIN_CLIENT_VAL, "Server");
+
+        os.write(PLAIN_SERVER_VAL);
+        os.flush();
+
+        for (int i = 1; i <= NUM_ITERATIONS; i++) {
+            if (VERBOSE) {
+                System.err.println("=================================");
+                System.err.println("Server Iteration #" + i);
+            }
+
+            SSLSocket ssls = (SSLSocket) sslsf.createSocket(plainSocket,
+                SERVER_NAME, plainSocket.getPort(), false);
+
+            ssls.setUseClientMode(false);
+            InputStream sslis = ssls.getInputStream();
+            OutputStream sslos = ssls.getOutputStream();
+
+            expectValue(sslis.read(), TLS_CLIENT_VAL, "Server");
+
+            sslos.write(TLS_SERVER_VAL);
+            sslos.flush();
+
+            sslis.close();
+            sslos.close();
+            ssls.close();
+
+            if (VERBOSE) {
+                System.err.println("TLS socket is closed");
+            }
+        }
+
+        expectValue(is.read(), PLAIN_CLIENT_VAL, "Server");
+
+        os.write(PLAIN_SERVER_VAL);
+        os.flush();
+
+        is.close();
+        os.close();
+        plainSocket.close();
+
+        if (VERBOSE) {
+            System.err.println("Server plain socket is closed");
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    private void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        if (VERBOSE) {
+            System.err.println("Starting client");
+        }
+
+        /*
+         * Setup the SSL stuff
+         */
+        SSLSocketFactory sslsf =
+             (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        Socket plainSocket = new Socket(SERVER_NAME, SERVER_PORT);
+        InputStream is = plainSocket.getInputStream();
+        OutputStream os = plainSocket.getOutputStream();
+
+        os.write(PLAIN_CLIENT_VAL);
+        os.flush();
+
+        expectValue(is.read(), PLAIN_SERVER_VAL, "Client");
+
+        for (int i = 1; i <= NUM_ITERATIONS; i++) {
+            if (VERBOSE) {
+                System.err.println("===================================");
+                System.err.println("Client Iteration #" + i);
+              }
+
+            SSLSocket ssls = (SSLSocket) sslsf.createSocket(plainSocket,
+               SERVER_NAME, plainSocket.getPort(), false);
+
+            ssls.setUseClientMode(true);
+
+            InputStream sslis = ssls.getInputStream();
+            OutputStream sslos = ssls.getOutputStream();
+
+            sslos.write(TLS_CLIENT_VAL);
+            sslos.flush();
+
+            expectValue(sslis.read(), TLS_SERVER_VAL, "Client");
+
+            sslis.close();
+            sslos.close();
+            ssls.close();
+
+            if (VERBOSE) {
+                System.err.println("Client TLS socket is closed");
+            }
+        }
+
+        os.write(PLAIN_CLIENT_VAL);
+        os.flush();
+
+        expectValue(is.read(), PLAIN_SERVER_VAL, "Client");
+
+        is.close();
+        os.close();
+        plainSocket.close();
+
+        if (VERBOSE) {
+            System.err.println("Client plain socket is closed");
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    private volatile int SERVER_PORT = 0;
+    private final static String SERVER_NAME = "localhost";
+
+    private volatile Exception serverException = null;
+    private volatile Exception clientException = null;
+
+    private final static String keyFilename =
+        System.getProperty("test.src", ".") + "/" + pathToStores +
+        "/" + keyStoreFile;
+    private final static String trustFilename =
+        System.getProperty("test.src", ".") + "/" + pathToStores +
+        "/" + trustStoreFile;
+
+
+   // Used for running test standalone
+    public static void main(String[] args) throws Exception {
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (DEBUG)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new NonAutoClose();
+    }
+
+    private Thread clientThread = null;
+    private Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    NonAutoClose() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.err.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.err.print("Client Exception:");
+            throw clientException;
+        }
+    }
+
+    private void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    private void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/RejectClientRenego.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2013, 2018, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 7188658
+ * @summary Add possibility to disable client initiated renegotiation
+ * @run main/othervm RejectClientRenego true SSLv3
+ * @run main/othervm RejectClientRenego false SSLv3
+ * @run main/othervm RejectClientRenego true TLSv1
+ * @run main/othervm RejectClientRenego false TLSv1
+ * @run main/othervm RejectClientRenego true TLSv1.1
+ * @run main/othervm RejectClientRenego false TLSv1.1
+ * @run main/othervm RejectClientRenego true TLSv1.2
+ * @run main/othervm RejectClientRenego false TLSv1.2
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.Security;
+import javax.net.ssl.*;
+
+public class RejectClientRenego implements
+        HandshakeCompletedListener {
+
+    static byte handshakesCompleted = 0;
+
+    /*
+     * Define what happens when handshaking is completed
+     */
+    public void handshakeCompleted(HandshakeCompletedEvent event) {
+        synchronized (this) {
+            handshakesCompleted++;
+            System.out.println("Session: " + event.getSession().toString());
+            System.out.println("Seen handshake completed #" +
+                handshakesCompleted);
+        }
+    }
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.setEnabledProtocols(new String[] { tlsProtocol });
+        sslSocket.addHandshakeCompletedListener(this);
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        try {
+            for (int i = 0; i < 10; i++) {
+                System.out.println("sending/receiving data, iteration: " + i);
+                sslIS.read();
+                sslOS.write(85);
+                sslOS.flush();
+            }
+            throw new Exception("Not reject client initialized renegotiation");
+        } catch (IOException ioe) {
+            System.out.println("Got the expected exception");
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledProtocols(new String[] { tlsProtocol });
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        if (!isAbbreviated) {
+            System.out.println("invalidating");
+            sslSocket.getSession().invalidate();
+        }
+        System.out.println("starting new handshake");
+        sslSocket.startHandshake();
+
+        try {
+            for (int i = 0; i < 10; i++) {
+                sslOS.write(280);
+                sslOS.flush();
+                sslIS.read();
+            }
+            throw new Exception("Not reject client initialized renegotiation");
+        } catch (IOException ioe) {
+            System.out.println("Got the expected exception");
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    // Is it abbreviated handshake?
+    private static boolean isAbbreviated = false;
+
+    // the specified protocol
+    private static String tlsProtocol;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        // reject client initialized SSL renegotiation.
+        System.setProperty(
+            "jdk.tls.rejectClientInitiatedRenegotiation", "true");
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        // Is it abbreviated handshake?
+        if ("true".equals(args[0])) {
+            isAbbreviated = true;
+        }
+
+        tlsProtocol = args[1];
+
+        /*
+         * Start the tests.
+         */
+        new RejectClientRenego();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    RejectClientRenego() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/SSLExceptionForIOIssue.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// Please run in othervm mode.  SunJSSE does not support dynamic system
+// properties, no way to re-use system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8214339
+ * @summary SSLSocketImpl erroneously wraps SocketException
+ * @library /javax/net/ssl/templates
+ * @run main/othervm SSLExceptionForIOIssue
+ */
+
+import javax.net.ssl.*;
+import java.io.*;
+import java.net.InetAddress;
+
+public class SSLExceptionForIOIssue implements SSLContextTemplate {
+
+    public static void main(String[] args) throws Exception {
+        System.err.println("===================================");
+        new SSLExceptionForIOIssue().test();
+    }
+
+    private void test() throws Exception {
+        SSLServerSocket listenSocket = null;
+        SSLSocket serverSocket = null;
+        ClientSocket clientSocket = null;
+        try {
+            SSLServerSocketFactory serversocketfactory =
+                    createServerSSLContext().getServerSocketFactory();
+            listenSocket =
+                    (SSLServerSocket)serversocketfactory.createServerSocket(0);
+            listenSocket.setNeedClientAuth(false);
+            listenSocket.setEnableSessionCreation(true);
+            listenSocket.setUseClientMode(false);
+
+            System.err.println("Starting client");
+            clientSocket = new ClientSocket(listenSocket.getLocalPort());
+            clientSocket.start();
+
+            System.err.println("Accepting client requests");
+            serverSocket = (SSLSocket)listenSocket.accept();
+
+            if (!clientSocket.isDone) {
+                System.err.println("Waiting 3 seconds for client ");
+                Thread.sleep(3000);
+            }
+
+            System.err.println("Sending data to client ...");
+            String serverData = "Hi, I am server";
+            BufferedWriter os = new BufferedWriter(
+                    new OutputStreamWriter(serverSocket.getOutputStream()));
+            os.write(serverData, 0, serverData.length());
+            os.newLine();
+            os.flush();
+        } catch (SSLProtocolException | SSLHandshakeException sslhe) {
+            throw sslhe;
+        } catch (SSLException ssle) {
+            // the expected exception, ignore it
+            System.err.println("server exception: " + ssle);
+        } finally {
+            if (listenSocket != null) {
+                listenSocket.close();
+            }
+
+            if (serverSocket != null) {
+                serverSocket.close();
+            }
+        }
+
+        if (clientSocket != null && clientSocket.clientException != null) {
+            throw clientSocket.clientException;
+        }
+    }
+
+
+
+    private class ClientSocket extends Thread{
+        boolean isDone = false;
+        int serverPort = 0;
+        Exception clientException;
+
+        public ClientSocket(int serverPort) {
+            this.serverPort = serverPort;
+        }
+
+        @Override
+        public void run() {
+            SSLSocket clientSocket = null;
+            String clientData = "Hi, I am client";
+            try {
+                System.err.println(
+                        "Connecting to server at port " + serverPort);
+                SSLSocketFactory sslSocketFactory =
+                        createClientSSLContext().getSocketFactory();
+                clientSocket = (SSLSocket)sslSocketFactory.createSocket(
+                        InetAddress.getLocalHost(), serverPort);
+                clientSocket.setSoLinger(true, 3);
+                clientSocket.setSoTimeout(100);
+
+
+                System.err.println("Sending data to server ...");
+
+                BufferedWriter os = new BufferedWriter(
+                        new OutputStreamWriter(clientSocket.getOutputStream()));
+                os.write(clientData, 0, clientData.length());
+                os.newLine();
+                os.flush();
+
+                System.err.println("Reading data from server");
+                BufferedReader is = new BufferedReader(
+                        new InputStreamReader(clientSocket.getInputStream()));
+                String data = is.readLine();
+                System.err.println("Received Data from server: " + data);
+            } catch (SSLProtocolException | SSLHandshakeException sslhe) {
+                clientException = sslhe;
+                System.err.println("unexpected client exception: " + sslhe);
+            } catch (SSLException ssle) {
+                // the expected exception, ignore it
+                System.err.println("expected client exception: " + ssle);
+            } catch (Exception e) {
+                clientException = e;
+                System.err.println("unexpected client exception: " + e);
+            } finally {
+                if (clientSocket != null) {
+                    try {
+                        clientSocket.close();
+                        System.err.println("client socket closed");
+                    } catch (IOException ioe) {
+                        clientException = ioe;
+                    }
+                }
+
+                isDone = true;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/SSLSocketImplThrowsWrongExceptions.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2001, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4361124 4325806
+ * @summary SSLServerSocket isn't throwing exceptions when negotiations are
+ *      failing & java.net.SocketException: occures in Auth and clientmode
+ * @run main/othervm SSLSocketImplThrowsWrongExceptions
+ * @author Brad Wetmore
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+public class SSLSocketImplThrowsWrongExceptions {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+
+    /*
+     * Define the server side of the test.
+     */
+    void doServerSide() throws Exception {
+        System.out.println("starting Server");
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+        System.out.println("got server socket");
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        try {
+            System.out.println("Server socket accepting...");
+            SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+            System.out.println("Server starting handshake");
+            sslSocket.startHandshake();
+            throw new Exception("Handshake was successful");
+        } catch (SSLException e) {
+            /*
+             * Caught the right Exeption.  Swallow it.
+             */
+            System.out.println("Server reported the right exception");
+            System.out.println(e.toString());
+        } catch (Exception e) {
+            /*
+             * Caught the wrong exception.  Rethrow it.
+             */
+            System.out.println("Server reported the wrong exception");
+            throw e;
+        }
+
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    void doClientSide() throws Exception {
+
+        System.out.println("    Client starting");
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        try {
+            System.out.println("        Client creating socket");
+            SSLSocket sslSocket = (SSLSocket)
+                sslsf.createSocket("localhost", serverPort);
+            System.out.println("        Client starting handshake");
+            sslSocket.startHandshake();
+            throw new Exception("Handshake was successful");
+        } catch (SSLException e) {
+            /*
+             * Caught the right Exception.  Swallow it.
+             */
+             System.out.println("       Client reported correct exception");
+             System.out.println("       " + e.toString());
+        } catch (Exception e) {
+            /*
+             * Caught the wrong exception.  Rethrow it.
+             */
+            System.out.println("        Client reported the wrong exception");
+            throw e;
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new SSLSocketImplThrowsWrongExceptions();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SSLSocketImplThrowsWrongExceptions () throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/SSLSocketKeyLimit.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8164879
+ * @library /lib/testlibrary ../../
+ * @modules java.base/sun.security.util
+ * @summary Verify AES/GCM's limits set in the jdk.tls.keyLimits property
+ * @run main SSLSocketKeyLimit 0 server AES/GCM/NoPadding keyupdate 1000000
+ * @run main SSLSocketKeyLimit 0 client AES/GCM/NoPadding keyupdate 1000000
+ * @run main SSLSocketKeyLimit 1 client AES/GCM/NoPadding keyupdate 2^22
+ */
+
+ /**
+  * Verify AES/GCM's limits set in the jdk.tls.keyLimits property
+  * start a new handshake sequence to renegotiate the symmetric key with an
+  * SSLSocket connection.  This test verifies the handshake method was called
+  * via debugging info.  It does not verify the renegotiation was successful
+  * as that is very hard.
+  */
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.util.Arrays;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Utils;
+import jdk.testlibrary.OutputAnalyzer;
+import sun.security.util.HexDumpEncoder;
+
+public class SSLSocketKeyLimit {
+    SSLSocket socket;
+    private InputStream in;
+    private OutputStream out;
+
+    static boolean serverReady = false;
+    static int serverPort = 0;
+
+    static String pathToStores = "../../../../javax/net/ssl/etc/";
+    static String keyStoreFile = "keystore";
+    static String passwd = "passphrase";
+    static int dataLen = 10240;
+    static byte[] data  = new byte[dataLen];
+    static boolean serverwrite = true;
+    int totalDataLen = 0;
+    static boolean done = false;
+
+    SSLSocketKeyLimit() {
+    }
+
+    SSLContext initContext() throws Exception {
+        SSLContext sc = SSLContext.getInstance("TLSv1.3");
+        KeyStore ks = KeyStore.getInstance(
+                new File(System.getProperty("javax.net.ssl.keyStore")),
+                passwd.toCharArray());
+        KeyManagerFactory kmf =
+                KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+        kmf.init(ks, passwd.toCharArray());
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+        tmf.init(ks);
+        sc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
+        return sc;
+    }
+
+    /**
+     * args should have two values:  server|client, <limit size>
+     * Prepending 'p' is for internal use only.
+     */
+    public static void main(String args[]) throws Exception {
+        if (args[0].compareTo("p") != 0) {
+
+            boolean expectedFail = (Integer.parseInt(args[0]) == 1);
+            if (expectedFail) {
+                System.out.println("Test expected to not find updated msg");
+            }
+            //Write security property file to overwrite default
+            File f = new File("keyusage."+ System.nanoTime());
+            PrintWriter p = new PrintWriter(f);
+            p.write("jdk.tls.keyLimits=");
+            for (int i = 2; i < args.length; i++) {
+                p.write(" "+ args[i]);
+            }
+            p.close();
+            System.out.println("Keyusage path = " + f.getAbsolutePath());
+            System.setProperty("test.java.opts",
+                    "-Dtest.src=" + System.getProperty("test.src") +
+                            " -Dtest.jdk=" + System.getProperty("test.jdk") +
+                            " -Djavax.net.debug=ssl,handshake" +
+                            " -Djava.security.properties=" + f.getName());
+
+            System.out.println("test.java.opts: " +
+                    System.getProperty("test.java.opts"));
+
+            ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+                    Utils.addTestJavaOpts("SSLSocketKeyLimit", "p", args[1]));
+
+            OutputAnalyzer output = ProcessTools.executeProcess(pb);
+            try {
+                if (expectedFail) {
+                    output.shouldNotContain("KeyUpdate: write key updated");
+                    output.shouldNotContain("KeyUpdate: read key updated");
+                } else {
+                    output.shouldContain("trigger key update");
+                    output.shouldContain("KeyUpdate: write key updated");
+                    output.shouldContain("KeyUpdate: read key updated");
+                }
+            } catch (Exception e) {
+                throw e;
+            } finally {
+                System.out.println("-- BEGIN Stdout:");
+                System.out.println(output.getStdout());
+                System.out.println("-- END Stdout");
+                System.out.println("-- BEGIN Stderr:");
+                System.out.println(output.getStderr());
+                System.out.println("-- END Stderr");
+            }
+            return;
+        }
+
+        if (args.length > 0 && args[0].compareToIgnoreCase("client") == 0) {
+            serverwrite = false;
+        }
+
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+
+        Arrays.fill(data, (byte)0x0A);
+        Thread ts = new Thread(new Server());
+
+        ts.start();
+        while (!serverReady) {
+            Thread.sleep(100);
+        }
+        new Client().run();
+        ts.join(10000);  // 10sec
+        System.exit(0);
+    }
+
+    void write(SSLSocket s) throws Exception {
+        int i = 0;
+        in = s.getInputStream();
+        out = s.getOutputStream();
+        while (i++ < 150) {
+            out.write(data, 0, dataLen);
+            System.out.print("W");
+            in.readNBytes(1);
+            System.out.print("R");
+        }
+        out.write(0x0D);
+        out.flush();
+
+        // Let read side all the data
+        while (!done) {
+            Thread.sleep(100);
+        }
+        out.close();
+        in.close();
+    }
+
+
+    void read(SSLSocket s) throws Exception {
+        byte[] buf = new byte[dataLen];
+        int len;
+        byte i = 0;
+        try {
+            System.out.println("Server: connected " + s.getSession().getCipherSuite());
+            in = s.getInputStream();
+            out = s.getOutputStream();
+            while (true) {
+                len = in.read(buf, 0, dataLen);
+                System.out.print("r");
+                out.write(i++);
+                System.out.print("w");
+                for (byte b: buf) {
+                    if (b == 0x0A || b == 0x0D) {
+                        continue;
+                    }
+                    System.out.println("\nData invalid: " + new HexDumpEncoder().encode(buf));
+                    break;
+                }
+
+                if (len > 0 && buf[len-1] == 0x0D) {
+                    System.out.println("got end byte");
+                    break;
+                }
+                totalDataLen += len;
+            }
+        } catch (Exception e) {
+            System.out.println("\n"  + e.getMessage());
+            e.printStackTrace();
+        } finally {
+            // Tell write side that we are done reading
+            out.close();
+            in.close();
+            done = true;
+        }
+        System.out.println("\nTotalDataLen = " + totalDataLen);
+    }
+
+    static class Server extends SSLSocketKeyLimit implements Runnable {
+        private SSLServerSocketFactory ssf;
+        private SSLServerSocket ss;
+        Server() {
+            super();
+            try {
+                ssf = initContext().getServerSocketFactory();
+                ss = (SSLServerSocket) ssf.createServerSocket(serverPort);
+                serverPort = ss.getLocalPort();
+            } catch (Exception e) {
+                System.out.println("server: " + e.getMessage());
+                e.printStackTrace();
+            }
+        }
+
+        public void run() {
+            try {
+                serverReady = true;
+                System.out.println("Server waiting... port: " + serverPort);
+                socket = (SSLSocket) ss.accept();
+                if (serverwrite) {
+                    write(socket);
+                } else {
+                    read(socket);
+                }
+
+                socket.close();
+            } catch (Exception e) {
+                System.out.println("server: " + e.getMessage());
+                e.printStackTrace();
+            }
+            System.out.println("Server closed");
+        }
+    }
+
+
+    static class Client extends SSLSocketKeyLimit implements Runnable {
+        private SSLSocketFactory sf;
+
+        Client() {
+            super();
+        }
+
+        public void run() {
+            try {
+                sf = initContext().getSocketFactory();
+                System.out.println("Client: connecting... port: " + serverPort);
+                socket = (SSLSocket)sf.createSocket("localhost", serverPort);
+                System.out.println("Client: connected." + socket.getSession().getCipherSuite());
+
+                // Opposite of what the server does
+                if (!serverwrite) {
+                    write(socket);
+                } else {
+                    read(socket);
+                }
+
+            } catch (Exception e) {
+                System.err.println("client: " + e.getMessage());
+                e.printStackTrace();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/ServerRenegoWithTwoVersions.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8208642
+ * @summary Server initiated TLSv1.2 renegotiation fails if Java
+ *      client allows TLSv1.3
+ * @run main/othervm ServerRenegoWithTwoVersions TLSv1 SSLv3
+ * @run main/othervm ServerRenegoWithTwoVersions TLSv1 TLSv1.1
+ * @run main/othervm ServerRenegoWithTwoVersions TLSv1.2 TLSv1.1
+ * @run main/othervm ServerRenegoWithTwoVersions TLSv1.3 TLSv1.2
+ */
+
+import java.io.*;
+import java.net.*;
+import java.security.Security;
+import javax.net.ssl.*;
+
+public class ServerRenegoWithTwoVersions implements
+        HandshakeCompletedListener {
+
+    static byte handshakesCompleted = 0;
+
+    /*
+     * Define what happens when handshaking is completed
+     */
+    public void handshakeCompleted(HandshakeCompletedEvent event) {
+        synchronized (this) {
+            handshakesCompleted++;
+            System.out.println("Session: " + event.getSession().toString());
+            System.out.println("Seen handshake completed #" +
+                handshakesCompleted);
+        }
+    }
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+        sslSocket.setEnabledProtocols(new String[] { serverProtocol });
+        sslSocket.addHandshakeCompletedListener(this);
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        System.out.println("invalidating");
+        sslSocket.getSession().invalidate();
+        System.out.println("starting new handshake");
+        sslSocket.startHandshake();
+
+        for (int i = 0; i < 10; i++) {
+            System.out.println("sending/receiving data, iteration: " + i);
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory)SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledProtocols(
+            new String[] { serverProtocol, clientProtocol });
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        for (int i = 0; i < 10; i++) {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    // the specified protocol
+    private static String clientProtocol;
+    private static String serverProtocol;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug) {
+            System.setProperty("javax.net.debug", "all");
+        }
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+
+        clientProtocol = args[0];
+        serverProtocol = args[1];
+
+        /*
+         * Start the tests.
+         */
+        new ServerRenegoWithTwoVersions();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ServerRenegoWithTwoVersions() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null) {
+            System.out.print("Server Exception:");
+            throw serverException;
+        }
+        if (clientException != null) {
+            System.out.print("Client Exception:");
+            throw clientException;
+        }
+
+        /*
+         * Give the Handshaker Thread a chance to run
+         */
+        Thread.sleep(1000);
+
+        synchronized (this) {
+            if (handshakesCompleted != 2) {
+                throw new Exception("Didn't see 2 handshake completed events.");
+            }
+        }
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SSLSocketImpl/SetClientMode.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2005, 2011, 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.
+ *
+ * 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.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 6223624
+ * @ignore this test does not grant to work.  The handshake may have completed
+ *        when getSession() return.  Please update or remove this test case.
+ * @summary SSLSocket.setUseClientMode() fails to throw expected
+ *        IllegalArgumentException
+ * @run main/othervm SetClientMode
+ */
+
+/*
+ * Attempts to replicate a TCK test failure which creates SSLServerSockets
+ * and then runs client threads which connect and start handshaking. Once
+ * handshaking is begun the server side attempts to invoke
+ * SSLSocket.setUseClientMode() on one or the other of the ends of the
+ * connection, expecting an IllegalArgumentException.
+ *
+ * If the server side of the connection tries setUseClientMode() we
+ * see the expected exception. If the setting is tried on the
+ * client side SSLSocket, we do *not* see the exception, except
+ * occasionally on the very first iteration.
+ */
+
+import java.io.*;
+import java.lang.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+
+public class SetClientMode {
+    private static String[] algorithms = {"TLS", "SSL", "SSLv3", "TLS"};
+    volatile int serverPort = 0;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+
+    public SetClientMode() {
+        // trivial constructor
+    }
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        new SetClientMode().run();
+    }
+
+    public void run() throws Exception {
+        for (int i = 0; i < algorithms.length; i++) {
+            testCombo( algorithms[i] );
+        }
+    }
+
+    public void testCombo(String algorithm) throws Exception {
+        Exception modeException = null ;
+
+        // Create a server socket
+        SSLServerSocketFactory ssf =
+            (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
+        SSLServerSocket serverSocket =
+            (SSLServerSocket)ssf.createServerSocket(serverPort);
+        serverPort = serverSocket.getLocalPort();
+
+        // Create a client socket
+        SSLSocketFactory sf = (SSLSocketFactory)SSLSocketFactory.getDefault();
+        SSLSocket clientSocket = (SSLSocket)sf.createSocket(
+                                InetAddress.getLocalHost(),
+                                serverPort );
+
+        // Create a client which will use the SSLSocket to talk to the server
+        SocketClient client = new SocketClient(clientSocket);
+
+        // Start the client and then accept any connection
+        client.start();
+
+        SSLSocket connectedSocket = (SSLSocket)serverSocket.accept();
+
+        // force handshaking to complete
+        connectedSocket.getSession();
+
+        try {
+            // Now try invoking setClientMode() on one
+            // or the other of our two sockets. We expect
+            // to see an IllegalArgumentException because
+            // handshaking has begun.
+            clientSocket.setUseClientMode(false);
+
+            modeException = new Exception("no IllegalArgumentException");
+        } catch (IllegalArgumentException iae) {
+            System.out.println("succeeded, we can't set the client mode");
+        } catch (Exception e) {
+            modeException = e;
+        } finally {
+            // Shut down.
+            connectedSocket.close();
+            serverSocket.close();
+
+            if (modeException != null) {
+                throw modeException;
+            }
+        }
+
+        return;
+    }
+
+    // A thread-based client which does nothing except
+    // start handshaking on the socket it's given.
+    class SocketClient extends Thread {
+        SSLSocket clientsideSocket;
+        Exception clientException = null;
+        boolean done = false;
+
+        public SocketClient( SSLSocket s ) {
+            clientsideSocket = s;
+        }
+
+        public void run() {
+            try {
+                clientsideSocket.startHandshake();
+
+                // If we were to invoke setUseClientMode()
+                // here, the expected exception will happen.
+                //clientsideSocket.getSession();
+                //clientsideSocket.setUseClientMode( false );
+            } catch ( Exception e ) {
+                e.printStackTrace();
+                clientException = e;
+            } finally {
+                done = true;
+                try {
+                    clientsideSocket.close();
+                } catch ( IOException e ) {
+                    // eat it
+                }
+            }
+            return;
+        }
+
+        boolean isDone() {
+            return done;
+        }
+
+        Exception getException() {
+            return clientException;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/ServerHandshaker/AnonCipherWithWantClientAuth.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2001, 2017, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 4392475
+ * @modules jdk.crypto.ec
+ * @library /javax/net/ssl/templates
+ * @summary Calling setWantClientAuth(true) disables anonymous suites
+ * @run main/othervm -Djavax.net.debug=all AnonCipherWithWantClientAuth
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Security;
+import javax.net.ssl.SSLSocket;
+
+public class AnonCipherWithWantClientAuth extends SSLSocketTemplate {
+    /*
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        (new AnonCipherWithWantClientAuth()).run();
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        String ciphers[] = {
+                "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+                "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" };
+        socket.setEnabledCipherSuites(ciphers);
+        socket.setWantClientAuth(true);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        String ciphers[] = {
+                "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+                "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5" };
+        socket.setEnabledCipherSuites(ciphers);
+        socket.setUseClientMode(true);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SignatureScheme/Tls13NamedGroups.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8225766
+ * @summary Curve in certificate should not affect signature scheme
+ *          when using TLSv1.3
+ * @library /javax/net/ssl/templates
+ * @run main/othervm Tls13NamedGroups
+ */
+
+import java.net.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.*;
+import java.security.cert.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+public class Tls13NamedGroups extends SSLSocketTemplate {
+
+    public static void main(String[] args) throws Exception {
+        // Limit the supported named group to secp521r1.
+        System.setProperty("jdk.tls.namedGroups", "secp521r1");
+
+        new Tls13NamedGroups().run();
+    }
+
+    @Override
+    protected SSLContext createServerSSLContext() throws Exception {
+        return generateSSLContext();
+    }
+
+    @Override
+    protected void configureServerSocket(SSLServerSocket socket) {
+        socket.setNeedClientAuth(true);
+    }
+
+    @Override
+    protected SSLContext createClientSSLContext() throws Exception {
+        return generateSSLContext();
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // Certificates and key used in the test.
+    //
+    // Trusted Certificate.
+    static String trustedCertStr =
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Subject Key Identifier:
+        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBvjCCAWOgAwIBAgIJAIvFG6GbTroCMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMDsxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n" +
+        "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABBz1WeVb6gM2mh85z3QlvaB/l11b5h0v\n" +
+        "LIzmkC3DKlVukZT+ltH2Eq1oEkpXuf7QmbM0ibrUgtjsWH3mULfmcWmjUDBOMB0G\n" +
+        "A1UdDgQWBBRgz71z//oaMNKk7NNJcUbvGjWghjAfBgNVHSMEGDAWgBRgz71z//oa\n" +
+        "MNKk7NNJcUbvGjWghjAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCG\n" +
+        "6wluh1r2/T6L31mZXRKf9JxeSf9pIzoLj+8xQeUChQIhAJ09wAi1kV8yePLh2FD9\n" +
+        "2YEHlSQUAbwwqCDEVB5KxaqP\n" +
+        "-----END CERTIFICATE-----";
+        // -----BEGIN PRIVATE KEY-----
+        // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/HcHdoLJCdq3haVd
+        // XZTSKP00YzM3xX97l98vGL/RI1KhRANCAAQc9VnlW+oDNpofOc90Jb2gf5ddW+Yd
+        // LyyM5pAtwypVbpGU/pbR9hKtaBJKV7n+0JmzNIm61ILY7Fh95lC35nFp
+        // -----END PRIVATE KEY-----
+
+    // End entity certificate.
+    static String targetCertStr =
+        // SHA256withECDSA, curve prime256v1
+        // Validity
+        //     Not Before: May 22 07:18:16 2018 GMT
+        //     Not After : May 17 07:18:16 2038 GMT
+        // Authority Key Identifier:
+        //     60:CF:BD:73:FF:FA:1A:30:D2:A4:EC:D3:49:71:46:EF:1A:35:A0:86
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBqjCCAVCgAwIBAgIJAPLY8qZjgNRAMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n" +
+        "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n" +
+        "ZTAeFw0xODA1MjIwNzE4MTZaFw0zODA1MTcwNzE4MTZaMFUxCzAJBgNVBAYTAlVT\n" +
+        "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEY\n" +
+        "MBYGA1UEAwwPUmVncmVzc2lvbiBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcD\n" +
+        "QgAEb+9n05qfXnfHUb0xtQJNS4JeSi6IjOfW5NqchvKnfJey9VkJzR7QHLuOESdf\n" +
+        "xlR7q8YIWgih3iWLGfB+wxHiOqMjMCEwHwYDVR0jBBgwFoAUYM+9c//6GjDSpOzT\n" +
+        "SXFG7xo1oIYwCgYIKoZIzj0EAwIDSAAwRQIgWpRegWXMheiD3qFdd8kMdrkLxRbq\n" +
+        "1zj8nQMEwFTUjjQCIQDRIrAjZX+YXHN9b0SoWWLPUq0HmiFIi8RwMnO//wJIGQ==\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8.
+    static String targetPrivateKey =
+        //
+        // EC private key related to cert endEntityCertStrs[0].
+        //
+        "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa\n" +
+        "JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM\n" +
+        "59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    // Create the SSLContext instance.
+    private static SSLContext generateSSLContext() throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        X509Certificate trusedCert = null;
+        ByteArrayInputStream is =
+                new ByteArrayInputStream(trustedCertStr.getBytes());
+        trusedCert = (X509Certificate)cf.generateCertificate(is);
+        is.close();
+
+        ks.setCertificateEntry("Trusted EC Signer", trusedCert);
+
+        // generate the private key.
+        PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                            Base64.getMimeDecoder().decode(targetPrivateKey));
+        KeyFactory kf = KeyFactory.getInstance("EC");
+        ECPrivateKey priKey =
+                (ECPrivateKey)kf.generatePrivate(priKeySpec);
+
+        // generate certificate chain
+        is = new ByteArrayInputStream(targetCertStr.getBytes());
+        X509Certificate keyCert = (X509Certificate)cf.generateCertificate(is);
+        is.close();
+
+        X509Certificate[] chain = new X509Certificate[2];
+        chain[0] = keyCert;
+        chain[1] = trusedCert;
+
+        // import the key entry and the chain
+        ks.setKeyEntry("TheKey", priKey, passphrase, chain);
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
+        tmf.init(ks);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(ks, passphrase);
+
+        SSLContext ctx = SSLContext.getInstance("TLSv1.3");
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        ks = null;
+
+        return ctx;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/SocketCreation/SocketCreation.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2001, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4414843
+ * @summary This test tries all the different ways in which an SSL
+ * connection can be established to exercise different SSLSocketImpl
+ * constructors.
+ * @run main/othervm/timeout=300 SocketCreation
+ *
+ *     SunJSSE does not support dynamic system properties, no way to re-use
+ *     system properties in samevm/agentvm mode.
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+
+/**
+ * This test has been adapted from JSSEClientServerTemplate.java. It runs
+ * the client and server multiple times while it iterates through the
+ * different ways in which an SSL connection can be established.
+ *
+ * The meat of this test is contained in doClientSide() and
+ * doServerSide(). The loop is contained in the constructor
+ * SocketCreation().
+ */
+public class SocketCreation {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Accepts a connection from a client and exchanges an int with it. The
+     * connection can be established in one of three different ways:
+     *    1. As a regular SSL server socket
+     *    2. As an SSL server socket that is first unbound
+     *    3. As an SSL socket layered over a regular TCP/IP socket
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide(int style) throws Exception {
+
+        Socket sslSocket = null;
+
+        // Change the for loop in SocketCreation() if you add more cases
+        switch (style) {
+        case 0:
+            sslSocket = acceptNormally0();
+            break;
+        case 1:
+            sslSocket = acceptNormally1();
+            break;
+        case 2:
+            sslSocket = acceptNormally2();
+            break;
+        case 3:
+            sslSocket = acceptUnbound();
+            break;
+        case 4:
+            sslSocket = acceptLayered();
+            break;
+        default:
+            throw new Exception("Incorrectly written test for server side!");
+        }
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        System.out.println("Server read: " + sslIS.read());
+        sslOS.write(85);
+        sslOS.flush();
+
+        sslSocket.close();
+    }
+
+    private Socket acceptNormally0() throws Exception {
+
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+
+        System.out.println("Server: Will call createServerSocket(int)");
+        ServerSocket sslServerSocket = sslssf.createServerSocket(0);
+        serverPort = sslServerSocket.getLocalPort();
+
+        System.out.println("Server: Will accept on SSL server socket...");
+
+        serverReady = true;
+
+        Socket sslSocket = sslServerSocket.accept();
+        sslServerSocket.close();
+        return sslSocket;
+    }
+
+    private Socket acceptNormally1() throws Exception {
+
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+
+        System.out.println("Server: Will call createServerSocket(int, int)");
+        ServerSocket sslServerSocket = sslssf.createServerSocket(0,
+                                                                 1);
+        serverPort = sslServerSocket.getLocalPort();
+
+        System.out.println("Server: Will accept on SSL server socket...");
+
+        serverReady = true;
+
+        Socket sslSocket = sslServerSocket.accept();
+        sslServerSocket.close();
+        return sslSocket;
+    }
+
+    private Socket acceptNormally2() throws Exception {
+
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+
+        System.out.println("Server: Will call createServerSocket(int, " +
+                           " int, InetAddress)");
+        ServerSocket sslServerSocket = sslssf.createServerSocket(0,
+                                         1,
+                                         InetAddress.getByName("localhost"));
+        serverPort = sslServerSocket.getLocalPort();
+
+        System.out.println("Server: Will accept on SSL server socket...");
+
+        serverReady = true;
+
+        Socket sslSocket = sslServerSocket.accept();
+        sslServerSocket.close();
+        return sslSocket;
+    }
+
+    private Socket acceptUnbound() throws Exception {
+
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+
+        System.out.println("Server: Will create unbound SSL server socket...");
+
+        ServerSocket sslServerSocket = sslssf.createServerSocket();
+
+        if (sslServerSocket.isBound())
+            throw new Exception("Server socket is already bound!");
+
+        sslServerSocket.bind(new java.net.InetSocketAddress(0));
+
+        if (!sslServerSocket.isBound())
+            throw new Exception("Server socket is not bound!");
+
+        serverPort = sslServerSocket.getLocalPort();
+        System.out.println("Server: Bound SSL server socket to port " +
+                serverPort + "...");
+
+        serverReady = true;
+
+        System.out.println("Server: Will accept on SSL server socket...");
+        Socket sslSocket = sslServerSocket.accept();
+        sslServerSocket.close();
+        return sslSocket;
+    }
+
+    private Socket acceptLayered() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        ServerSocket ss = new ServerSocket(0);
+        serverPort = ss.getLocalPort();
+        System.out.println("Server: Created normal server socket bound"
+                + " to port " + serverPort + "...");
+        System.out.println("Server: Will accept on server socket...");
+        serverReady = true;
+        Socket s = ss.accept();
+        ss.close();
+        System.out.println("Server: Will layer SSLSocket on top of" +
+                           " server socket...");
+        SSLSocket sslSocket =
+            (SSLSocket) sslsf.createSocket(s,
+                                            s.getInetAddress().getHostName(),
+                                            s.getPort(),
+                                            true);
+        sslSocket.setUseClientMode(false);
+
+        return sslSocket;
+    }
+
+    /*
+     * Connects to a server and exchanges an int with it. The
+     * connection can be established in one of three different ways:
+     *    1. As a regular SSL socket
+     *    2. As an SSL socket that is first unconnected
+     *    3. As an SSL socket layered over a regular TCP/IP socket
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide(int style) throws Exception {
+
+        Socket sslSocket = null;
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        // Change the for loop in SocketCreation() if you add more cases
+        switch (style) {
+        case 0:
+            sslSocket = connectNormally0();
+            break;
+        case 1:
+            sslSocket = connectNormally1();
+            break;
+        case 2:
+            sslSocket = connectNormally2();
+            break;
+        case 3:
+            sslSocket = connectNormally3();
+            break;
+        case 4:
+            sslSocket = connectUnconnected();
+            break;
+        case 5:
+            sslSocket = connectLayered();
+            break;
+        default:
+            throw new Exception("Incorrectly written test for client side!");
+        }
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        System.out.println("Client read: " + sslIS.read());
+
+        sslSocket.close();
+    }
+
+    private Socket connectNormally0() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        System.out.println("Client: Will call createSocket(String, int)");
+        return sslsf.createSocket("localhost", serverPort);
+    }
+
+    private Socket connectNormally1() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        System.out.println("Client: Will call createSocket(InetAddress, int)");
+        return sslsf.createSocket(InetAddress.getByName("localhost"),
+                                  serverPort);
+    }
+
+    private Socket connectNormally2() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        System.out.println("Client: Will call createSocket(String," +
+                           " int, InetAddress, int)");
+        return sslsf.createSocket("localhost", serverPort,
+                                  InetAddress.getByName("localhost"),
+                                  0);
+    }
+
+    private Socket connectNormally3() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        System.out.println("Client: Will call createSocket(InetAddress," +
+                           " int, InetAddress, int)");
+        return sslsf.createSocket(InetAddress.getByName("localhost"),
+                                  serverPort,
+                                  InetAddress.getByName("localhost"),
+                                  0);
+    }
+
+    private Socket connectUnconnected() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        System.out.println("Client: Will call createSocket()");
+        Socket sslSocket = sslsf.createSocket();
+
+        if (sslSocket.isConnected())
+            throw new Exception("Client socket is already connected!");
+
+        System.out.println("Client: Will connect to server on port " +
+                           serverPort + "...");
+        sslSocket.connect(new java.net.InetSocketAddress("localhost",
+                                                         serverPort));
+
+        if (!sslSocket.isConnected())
+            throw new Exception("Client socket is not connected!");
+
+        return sslSocket;
+    }
+
+    private Socket connectLayered() throws Exception {
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+        System.out.println("Client: Will connect to server on port " +
+                           serverPort + "...");
+        Socket s = new Socket("localhost", serverPort);
+
+        System.out.println("Client: Will layer SSL socket on top...");
+        return sslsf.createSocket(s, "localhost", serverPort, true);
+
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new SocketCreation();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Performs a loop where each iteration establishes one client-server
+     * connection using a particular way of socket creation. There are
+     * three ways in each side can create a socket:
+     *   1. Normal (The client has 4 variations of this and the server 3)
+     *   2. Unbound/Unconnected
+     *   3. Layered
+     * Each side goes through all three of them giving us a total of 5x6
+     * possibilites.
+     */
+    SocketCreation() throws Exception {
+
+        for (int serverStyle = 0; serverStyle < 5; serverStyle++) {
+            System.out.println("-------------------------------------");
+            for (int clientStyle = 0; clientStyle < 6; clientStyle++) {
+
+                serverReady = false;
+
+                startServer(separateServerThread, serverStyle);
+                startClient(!separateServerThread, clientStyle);
+
+                /*
+                 * Wait for other side to close down.
+                 */
+                if (separateServerThread) {
+                    serverThread.join();
+                } else {
+                    clientThread.join();
+                }
+
+                /*
+                 * When we get here, the test is pretty much over.
+                 *
+                 * If the main thread excepted, that propagates back
+                 * immediately.  If the other thread threw an exception, we
+                 * should report back.
+                 */
+                if (serverException != null)
+                    throw serverException;
+                if (clientException != null)
+                    throw clientException;
+                System.out.println();
+            }
+        }
+    }
+
+    void startServer(boolean newThread, final int style) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide(style);
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died..." + e);
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide(style);
+        }
+    }
+
+    void startClient(boolean newThread, final int style) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide(style);
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide(style);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/Stapling/StatusResponseManager.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8046321
+ * @library ../../../../java/security/testlibrary
+ * @build CertificateBuilder SimpleOCSPServer
+ * @run main/othervm -Djavax.net.debug=ssl:respmgr java.base/sun.security.ssl.StatusResponseManagerTests
+ * @summary OCSP Stapling for TLS
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/Stapling/java.base/sun/security/ssl/StatusResponseManagerTests.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2015, 2016, 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.
+ *
+ * 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.math.BigInteger;
+import java.security.cert.*;
+import java.util.*;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.PublicKey;
+import java.util.concurrent.TimeUnit;
+
+import sun.security.testlibrary.SimpleOCSPServer;
+import sun.security.testlibrary.CertificateBuilder;
+
+import static sun.security.ssl.CertStatusExtension.*;
+
+/*
+ * Checks that the hash value for a certificate's issuer name is generated
+ * correctly. Requires any certificate that is not self-signed.
+ *
+ * NOTE: this test uses Sun private classes which are subject to change.
+ */
+public class StatusResponseManagerTests {
+
+    private static final boolean debug = true;
+    private static final boolean ocspDebug = false;
+
+    // PKI components we will need for this test
+    static String passwd = "passphrase";
+    static String ROOT_ALIAS = "root";
+    static String INT_ALIAS = "intermediate";
+    static String SSL_ALIAS = "ssl";
+    static KeyStore rootKeystore;           // Root CA Keystore
+    static KeyStore intKeystore;            // Intermediate CA Keystore
+    static KeyStore serverKeystore;         // SSL Server Keystore
+    static KeyStore trustStore;             // SSL Client trust store
+    static X509Certificate rootCert;
+    static X509Certificate intCert;
+    static X509Certificate sslCert;
+    static SimpleOCSPServer rootOcsp;       // Root CA OCSP Responder
+    static int rootOcspPort;                // Port number for root OCSP
+    static SimpleOCSPServer intOcsp;        // Intermediate CA OCSP Responder
+    static int intOcspPort;                 // Port number for intermed. OCSP
+
+    static X509Certificate[] chain;
+
+    public static void main(String[] args) throws Exception {
+        Map<String, TestCase> testList =
+                new LinkedHashMap<String, TestCase>() {{
+            put("Basic OCSP fetch test", testOcspFetch);
+            put("Clear StatusResponseManager cache", testClearSRM);
+            put("Basic OCSP_MULTI fetch test", testOcspMultiFetch);
+            put("Test Cache Expiration", testCacheExpiry);
+        }};
+
+        // Create the CAs and OCSP responders
+        createPKI();
+
+        // Grab the certificates and make a chain we can reuse for tests
+        sslCert = (X509Certificate)serverKeystore.getCertificate(SSL_ALIAS);
+        intCert = (X509Certificate)intKeystore.getCertificate(INT_ALIAS);
+        rootCert = (X509Certificate)rootKeystore.getCertificate(ROOT_ALIAS);
+        chain = new X509Certificate[3];
+        chain[0] = sslCert;
+        chain[1] = intCert;
+        chain[2] = rootCert;
+
+        runTests(testList);
+
+        intOcsp.stop();
+        rootOcsp.stop();
+    }
+
+    // Test a simple RFC 6066 server-side fetch
+    public static final TestCase testOcspFetch = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            CertStatusRequest oReq = OCSPStatusRequest.EMPTY_OCSP;
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                Map<X509Certificate, byte[]> responseMap = srm.get(
+                        CertStatusRequestType.OCSP, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be one entry in the returned map and
+                // one entry in the cache when the operation is complete.
+                if (responseMap.size() != 1) {
+                    message = "Incorrect number of responses: expected 1, got "
+                            + responseMap.size();
+                } else if (!responseMap.containsKey(sslCert)) {
+                    message = "Response map key is incorrect, expected " +
+                            sslCert.getSubjectX500Principal().toString();
+                } else if (srm.size() != 1) {
+                    message = "Incorrect number of cache entries: " +
+                            "expected 1, got " + srm.size();
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test clearing the StatusResponseManager cache.
+    public static final TestCase testClearSRM = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            CertStatusRequest oReq = OCSPStatusRequest.EMPTY_OCSP_MULTI;
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                srm.get(CertStatusRequestType.OCSP_MULTI, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be two entries in the returned map and
+                // two entries in the cache when the operation is complete.
+                if (srm.size() != 2) {
+                    message = "Incorrect number of responses: expected 2, got "
+                            + srm.size();
+                } else {
+                    // Next, clear the SRM, then check the size again
+                    srm.clear();
+                    if (srm.size() != 0) {
+                        message = "Incorrect number of responses: expected 0," +
+                                " got " + srm.size();
+                    } else {
+                        pass = Boolean.TRUE;
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test a simple RFC 6961 server-side fetch
+    public static final TestCase testOcspMultiFetch = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            CertStatusRequest oReq = OCSPStatusRequest.EMPTY_OCSP_MULTI;
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                Map<X509Certificate, byte[]> responseMap = srm.get(
+                        CertStatusRequestType.OCSP_MULTI, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be two entries in the returned map and
+                // two entries in the cache when the operation is complete.
+                if (responseMap.size() != 2) {
+                    message = "Incorrect number of responses: expected 2, got "
+                            + responseMap.size();
+                } else if (!responseMap.containsKey(sslCert) ||
+                        !responseMap.containsKey(intCert)) {
+                    message = "Response map keys are incorrect, expected " +
+                            sslCert.getSubjectX500Principal().toString() +
+                            " and " +
+                            intCert.getSubjectX500Principal().toString();
+                } else if (srm.size() != 2) {
+                    message = "Incorrect number of cache entries: " +
+                            "expected 2, got " + srm.size();
+                } else {
+                    pass = Boolean.TRUE;
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    // Test cache expiration
+    public static final TestCase testCacheExpiry = new TestCase() {
+        @Override
+        public Map.Entry<Boolean, String> runTest() {
+            // For this test, we will set the cache expiry to 5 seconds
+            System.setProperty("jdk.tls.stapling.cacheLifetime", "5");
+            StatusResponseManager srm = new StatusResponseManager();
+            Boolean pass = Boolean.FALSE;
+            String message = null;
+            CertStatusRequest oReq = OCSPStatusRequest.EMPTY_OCSP_MULTI;
+
+            try {
+                // Get OCSP responses for non-root certs in the chain
+                srm.get(CertStatusRequestType.OCSP_MULTI, oReq, chain, 5000,
+                        TimeUnit.MILLISECONDS);
+
+                // There should be two entries in the returned map and
+                // two entries in the cache when the operation is complete.
+                if (srm.size() != 2) {
+                    message = "Incorrect number of responses: expected 2, got "
+                            + srm.size();
+                } else {
+                    // Next, wait for more than 5 seconds so the responses
+                    // in the SRM will expire.
+                    Thread.sleep(7000);
+                    if (srm.size() != 0) {
+                        message = "Incorrect number of responses: expected 0," +
+                                " got " + srm.size();
+                    } else {
+                        pass = Boolean.TRUE;
+                    }
+                }
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                message = e.getClass().getName();
+            }
+
+            // Set the cache lifetime back to the default
+            System.setProperty("jdk.tls.stapling.cacheLifetime", "");
+            return new AbstractMap.SimpleEntry<>(pass, message);
+        }
+    };
+
+    /**
+     * Creates the PKI components necessary for this test, including
+     * Root CA, Intermediate CA and SSL server certificates, the keystores
+     * for each entity, a client trust store, and starts the OCSP responders.
+     */
+    private static void createPKI() throws Exception {
+        CertificateBuilder cbld = new CertificateBuilder();
+        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+        keyGen.initialize(2048);
+        KeyStore.Builder keyStoreBuilder =
+                KeyStore.Builder.newInstance("PKCS12", null,
+                        new KeyStore.PasswordProtection(passwd.toCharArray()));
+
+        // Generate Root, IntCA, EE keys
+        KeyPair rootCaKP = keyGen.genKeyPair();
+        log("Generated Root CA KeyPair");
+        KeyPair intCaKP = keyGen.genKeyPair();
+        log("Generated Intermediate CA KeyPair");
+        KeyPair sslKP = keyGen.genKeyPair();
+        log("Generated SSL Cert KeyPair");
+
+        // Set up the Root CA Cert
+        cbld.setSubjectName("CN=Root CA Cert, O=SomeCompany");
+        cbld.setPublicKey(rootCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("1"));
+        // Make a 3 year validity starting from 60 days ago
+        long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60);
+        long end = start + TimeUnit.DAYS.toMillis(1085);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, rootCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        // Make our Root CA Cert!
+        X509Certificate rootCert = cbld.build(null, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Root CA Created:\n" + certInfo(rootCert));
+
+        // Now build a keystore and add the keys and cert
+        rootKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] rootChain = {rootCert};
+        rootKeystore.setKeyEntry(ROOT_ALIAS, rootCaKP.getPrivate(),
+                passwd.toCharArray(), rootChain);
+
+        // Now fire up the OCSP responder
+        rootOcsp = new SimpleOCSPServer(rootKeystore, passwd, ROOT_ALIAS, null);
+        rootOcsp.enableLog(ocspDebug);
+        rootOcsp.setNextUpdateInterval(3600);
+        rootOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !rootOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!rootOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        rootOcspPort = rootOcsp.getPort();
+        String rootRespURI = "http://localhost:" + rootOcspPort;
+        log("Root OCSP Responder URI is " + rootRespURI);
+
+        // Now that we have the root keystore and OCSP responder we can
+        // create our intermediate CA.
+        cbld.reset();
+        cbld.setSubjectName("CN=Intermediate CA Cert, O=SomeCompany");
+        cbld.setPublicKey(intCaKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("100"));
+        // Make a 2 year validity starting from 30 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(30);
+        end = start + TimeUnit.DAYS.toMillis(730);
+        cbld.setValidity(new Date(start), new Date(end));
+        addCommonExts(cbld, intCaKP.getPublic(), rootCaKP.getPublic());
+        addCommonCAExts(cbld);
+        cbld.addAIAExt(Collections.singletonList(rootRespURI));
+        // Make our Intermediate CA Cert!
+        X509Certificate intCaCert = cbld.build(rootCert, rootCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("Intermediate CA Created:\n" + certInfo(intCaCert));
+
+        // Provide intermediate CA cert revocation info to the Root CA
+        // OCSP responder.
+        Map<BigInteger, SimpleOCSPServer.CertStatusInfo> revInfo =
+            new HashMap<>();
+        revInfo.put(intCaCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        rootOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        intKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] intChain = {intCaCert, rootCert};
+        intKeystore.setKeyEntry(INT_ALIAS, intCaKP.getPrivate(),
+                passwd.toCharArray(), intChain);
+        intKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // Now fire up the Intermediate CA OCSP responder
+        intOcsp = new SimpleOCSPServer(intKeystore, passwd,
+                INT_ALIAS, null);
+        intOcsp.enableLog(ocspDebug);
+        intOcsp.setNextUpdateInterval(3600);
+        intOcsp.start();
+
+        // Wait 5 seconds for server ready
+        for (int i = 0; (i < 100 && !intOcsp.isServerReady()); i++) {
+            Thread.sleep(50);
+        }
+        if (!intOcsp.isServerReady()) {
+            throw new RuntimeException("Server not ready yet");
+        }
+
+        intOcspPort = intOcsp.getPort();
+        String intCaRespURI = "http://localhost:" + intOcspPort;
+        log("Intermediate CA OCSP Responder URI is " + intCaRespURI);
+
+        // Last but not least, let's make our SSLCert and add it to its own
+        // Keystore
+        cbld.reset();
+        cbld.setSubjectName("CN=SSLCertificate, O=SomeCompany");
+        cbld.setPublicKey(sslKP.getPublic());
+        cbld.setSerialNumber(new BigInteger("4096"));
+        // Make a 1 year validity starting from 7 days ago
+        start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7);
+        end = start + TimeUnit.DAYS.toMillis(365);
+        cbld.setValidity(new Date(start), new Date(end));
+
+        // Add extensions
+        addCommonExts(cbld, sslKP.getPublic(), intCaKP.getPublic());
+        boolean[] kuBits = {true, false, true, false, false, false,
+            false, false, false};
+        cbld.addKeyUsageExt(kuBits);
+        List<String> ekuOids = new ArrayList<>();
+        ekuOids.add("1.3.6.1.5.5.7.3.1");
+        ekuOids.add("1.3.6.1.5.5.7.3.2");
+        cbld.addExtendedKeyUsageExt(ekuOids);
+        cbld.addSubjectAltNameDNSExt(Collections.singletonList("localhost"));
+        cbld.addAIAExt(Collections.singletonList(intCaRespURI));
+        // Make our SSL Server Cert!
+        X509Certificate sslCert = cbld.build(intCaCert, intCaKP.getPrivate(),
+                "SHA256withRSA");
+        log("SSL Certificate Created:\n" + certInfo(sslCert));
+
+        // Provide SSL server cert revocation info to the Intermeidate CA
+        // OCSP responder.
+        revInfo = new HashMap<>();
+        revInfo.put(sslCert.getSerialNumber(),
+                new SimpleOCSPServer.CertStatusInfo(
+                        SimpleOCSPServer.CertStatus.CERT_STATUS_GOOD));
+        intOcsp.updateStatusDb(revInfo);
+
+        // Now build a keystore and add the keys, chain and root cert as a TA
+        serverKeystore = keyStoreBuilder.getKeyStore();
+        Certificate[] sslChain = {sslCert, intCaCert, rootCert};
+        serverKeystore.setKeyEntry(SSL_ALIAS, sslKP.getPrivate(),
+                passwd.toCharArray(), sslChain);
+        serverKeystore.setCertificateEntry(ROOT_ALIAS, rootCert);
+
+        // And finally a Trust Store for the client
+        trustStore = keyStoreBuilder.getKeyStore();
+        trustStore.setCertificateEntry(ROOT_ALIAS, rootCert);
+    }
+
+    private static void addCommonExts(CertificateBuilder cbld,
+            PublicKey subjKey, PublicKey authKey) throws IOException {
+        cbld.addSubjectKeyIdExt(subjKey);
+        cbld.addAuthorityKeyIdExt(authKey);
+    }
+
+    private static void addCommonCAExts(CertificateBuilder cbld)
+            throws IOException {
+        cbld.addBasicConstraintsExt(true, true, -1);
+        // Set key usage bits for digitalSignature, keyCertSign and cRLSign
+        boolean[] kuBitSettings = {true, false, false, false, false, true,
+            true, false, false};
+        cbld.addKeyUsageExt(kuBitSettings);
+    }
+
+    /**
+     * Helper routine that dumps only a few cert fields rather than
+     * the whole toString() output.
+     *
+     * @param cert An X509Certificate to be displayed
+     *
+     * @return The {@link String} output of the issuer, subject and
+     * serial number
+     */
+    private static String certInfo(X509Certificate cert) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Issuer: ").append(cert.getIssuerX500Principal()).
+                append("\n");
+        sb.append("Subject: ").append(cert.getSubjectX500Principal()).
+                append("\n");
+        sb.append("Serial: ").append(cert.getSerialNumber()).append("\n");
+        return sb.toString();
+    }
+
+    /**
+     * Log a message on stdout
+     *
+     * @param message The message to log
+     */
+    private static void log(String message) {
+        if (debug) {
+            System.out.println(message);
+        }
+    }
+
+    public static void runTests(Map<String, TestCase> testList) {
+        int testNo = 0;
+        int numberFailed = 0;
+        Map.Entry<Boolean, String> result;
+
+        System.out.println("============ Tests ============");
+        for (String testName : testList.keySet()) {
+            System.out.println("Test " + ++testNo + ": " + testName);
+            result = testList.get(testName).runTest();
+            System.out.print("Result: " + (result.getKey() ? "PASS" : "FAIL"));
+            System.out.println(" " +
+                    (result.getValue() != null ? result.getValue() : ""));
+            System.out.println("-------------------------------------------");
+            if (!result.getKey()) {
+                numberFailed++;
+            }
+        }
+
+        System.out.println("End Results: " + (testList.size() - numberFailed) +
+                " Passed" + ", " + numberFailed + " Failed.");
+        if (numberFailed > 0) {
+            throw new RuntimeException(
+                    "One or more tests failed, see test output for details");
+        }
+    }
+
+    public interface TestCase {
+        Map.Entry<Boolean, String> runTest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/X509TrustManagerImpl/BasicConstraints.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,565 @@
+/*
+ * Copyright (c) 2012, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7166570
+ * @summary JSSE certificate validation has started to fail for
+ *     certificate chains
+ * @run main/othervm BasicConstraints PKIX
+ * @run main/othervm BasicConstraints SunX509
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.*;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.math.BigInteger;
+
+import java.util.Base64;
+
+public class BasicConstraints {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificate information:
+    // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce
+    // Validity
+    //     Not Before: May  5 02:40:50 2012 GMT
+    //     Not After : Apr 15 02:40:50 2033 GMT
+    // Subject: C=US, O=Java, OU=SunJSSE Test Serivce
+    // X509v3 Subject Key Identifier:
+    //     DD:4E:8D:2A:11:C0:83:03:F0:AC:EB:A2:BF:F9:F2:7D:C8:69:1F:9B
+    // X509v3 Authority Key Identifier:
+    //     keyid:DD:4E:8D:2A:11:C0:83:03:F0:AC:EB:A2:BF:F9:F2:7D:C8:69:1F:9B
+    //     DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
+    //     serial:00
+    static String trusedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICkjCCAfugAwIBAgIBADANBgkqhkiG9w0BAQIFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNTA1MDI0MDUwWhcNMzMwNDE1MDI0MDUwWjA7MQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwgZ8wDQYJ\n" +
+        "KoZIhvcNAQEBBQADgY0AMIGJAoGBANtiq0AIJK+iVRwFrqcD7fYXTCbMYC5Qz/k6\n" +
+        "AXBy7/1rI8wDhEJLE3m/+NSqiJwZcmdq2dNh/1fJFrwvzuURbc9+paOBWeHbN+Sc\n" +
+        "x3huw91oPZme385VpoK3G13rSE114S/rF4DM9mz4EStFhSHXATjtdbskNOAYGLTV\n" +
+        "x8uEy9GbAgMBAAGjgaUwgaIwHQYDVR0OBBYEFN1OjSoRwIMD8Kzror/58n3IaR+b\n" +
+        "MGMGA1UdIwRcMFqAFN1OjSoRwIMD8Kzror/58n3IaR+boT+kPTA7MQswCQYDVQQG\n" +
+        "EwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2\n" +
+        "Y2WCAQAwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEC\n" +
+        "BQADgYEAjjkJesQrkbr36N40egybaIxw7RcqT6iy5fkAGS1JYlBDk8uSCK1o6bCH\n" +
+        "ls5EpYcGeEoabSS73WRdkO1lgeyWDduO4ef8cCCSpmpT6/YdZG0QS1PtcREeVig+\n" +
+        "Zr25jNemS4ADHX0aaXP4kiV/G80cR7nX5t5XCUm4bYdbwM07NgI=\n" +
+        "-----END CERTIFICATE-----";
+    static String trustedPrivateKey = // Private key in the format of PKCS#8
+        "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANtiq0AIJK+iVRwF\n" +
+        "rqcD7fYXTCbMYC5Qz/k6AXBy7/1rI8wDhEJLE3m/+NSqiJwZcmdq2dNh/1fJFrwv\n" +
+        "zuURbc9+paOBWeHbN+Scx3huw91oPZme385VpoK3G13rSE114S/rF4DM9mz4EStF\n" +
+        "hSHXATjtdbskNOAYGLTVx8uEy9GbAgMBAAECgYEA2VjHkIiA0ABjkX+PqKeb+VLb\n" +
+        "fxS7tSca5C8zfdRhLxAWRui0/3ihst0eCJNrBDuxvAOACovsDWyLuaUjtI2v2ysz\n" +
+        "vz6SPyGy82PhQOFzyKQuQ814N6EpothpiZzF0yFchfKIGhUsdY89UrGs9nM7m6NT\n" +
+        "rztYvgIu4avg2VPR2AECQQD+pFAqipR2BplQRIuuRSZfHRxvoEyDjT1xnHJsC6WP\n" +
+        "I5hCLghL91MhQGWbP4EJMKYQOTRVukWlcp2Kycpf+P5hAkEA3I43gmVUAPEdyZdY\n" +
+        "fatW7OaLlbbYJb6qEtpCZ1Rwe/BIvm6H6E3qSi/lpz7Ia7WDulpbF6BawHH3pRFq\n" +
+        "CUY5ewJBAP3pUDqrRpBN0jB0uSeDslhjSciQ+dqvSpZv3rSYBHUvlBJhnkpJiy37\n" +
+        "7ZUZhIxqYxyIPgRBolLwb+FFh7OdL+ECQCtldDic9WVmC+VheRDpCKZ+SlK/8lGi\n" +
+        "7VXeShiIvcU1JysJFoa35fSI7hf1O3wt7+hX5PqGG7Un94EsJwACKEcCQQC1TWt6\n" +
+        "ArKH6tRxKjOxFtqfs8fgEVYUaOr3j1jF4KBUuX2mtQtddZe3VfJ2wPsuKMMxmhkB\n" +
+        "e7xWWZnJsErt2e+E";
+
+    // Certificate information:
+    // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce
+    // Validity
+    //     Not Before: May  5 02:40:53 2012 GMT
+    //     Not After : Jan 21 02:40:53 2032 GMT
+    // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=casigner
+    // X509v3 Subject Key Identifier:
+    //     13:07:E0:11:07:DB:EB:33:23:87:31:D0:DB:7E:16:56:BE:11:90:0A
+    // X509v3 Authority Key Identifier:
+    //     keyid:DD:4E:8D:2A:11:C0:83:03:F0:AC:EB:A2:BF:F9:F2:7D:C8:69:1F:9B
+    //     DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
+    //     serial:00
+    static String caSignerStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICqDCCAhGgAwIBAgIBAjANBgkqhkiG9w0BAQQFADA7MQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UwHhcN\n" +
+        "MTIwNTA1MDI0MDUzWhcNMzIwMTIxMDI0MDUzWjBOMQswCQYDVQQGEwJVUzENMAsG\n" +
+        "A1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxETAPBgNV\n" +
+        "BAMTCGNhc2lnbmVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+x8+o7oM0\n" +
+        "ct/LZmZLXBL4CQ8jrULD5P7NtEW0hg/zxBFZfBHf+44Oo2eMPYZj+7xaREOH5BmV\n" +
+        "KRYlzRtONAaC5Ng4Mrm5UKNPcMIIUjUOvm7vWM4oSTMSfoEcSX+vp99uUAkw3w7Z\n" +
+        "+frYDm1M4At/j0b+lLij71GFN2L8drpgPQIDAQABo4GoMIGlMB0GA1UdDgQWBBQT\n" +
+        "B+ARB9vrMyOHMdDbfhZWvhGQCjBjBgNVHSMEXDBagBTdTo0qEcCDA/Cs66K/+fJ9\n" +
+        "yGkfm6E/pD0wOzELMAkGA1UEBhMCVVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsT\n" +
+        "FFN1bkpTU0UgVGVzdCBTZXJpdmNlggEAMBIGA1UdEwEB/wQIMAYBAf8CAQEwCwYD\n" +
+        "VR0PBAQDAgEGMA0GCSqGSIb3DQEBBAUAA4GBAI+LXA/UCPkTANablUkt80JNPWsl\n" +
+        "pS4XLNgPxWaN0bkRDs5oI4ooWAz1rwpeJ/nfetOvWlpmrVjSeovBFja5Hl+dUHTf\n" +
+        "VfuyzkxXbhuNiJIpo1mVBpNsjwu9YRxuwX6UA2LTUQpgvtVJEE012x3zRvxBCbu2\n" +
+        "Y/v1R5fZ4c+hXDfC\n" +
+        "-----END CERTIFICATE-----";
+    static String caSignerPrivateKey = // Private key in the format of PKCS#8
+        "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAL7Hz6jugzRy38tm\n" +
+        "ZktcEvgJDyOtQsPk/s20RbSGD/PEEVl8Ed/7jg6jZ4w9hmP7vFpEQ4fkGZUpFiXN\n" +
+        "G040BoLk2DgyublQo09wwghSNQ6+bu9YzihJMxJ+gRxJf6+n325QCTDfDtn5+tgO\n" +
+        "bUzgC3+PRv6UuKPvUYU3Yvx2umA9AgMBAAECgYBYvu30cW8LONyt62Zua9hPFTe7\n" +
+        "qt9B7QYyfkdmoG5PQMepTrOp84SzfoOukvgvDm0huFuJnSvhXQl2cCDhkgXskvFj\n" +
+        "Hh7KBCFViVXokGdq5YoS0/KYMyQV0TZfJUvILBl51uc4/siQ2tClC/N4sa+1JhgW\n" +
+        "a6dFGfRjiUKSSlmMwQJBAPWpIz3Q/c+DYMvoQr5OD8EaYwYIevlTdXb97RnJJh2b\n" +
+        "UnhB9jrqesJiHYVzPmP0ukyPOXOwlp2T5Am4Kw0LFOkCQQDGz150NoHOp28Mvyc4\n" +
+        "CTqz/zYzUhy2eCJESl196uyP4N65Y01VYQ3JDww4DlsXiU17tVSbgA9TCcfTYOzy\n" +
+        "vyw1AkARUky+1hafZCcWGZljK8PmnMKwsTZikCTvL/Zg5BMA8Wu+OQBwpQnk3OAy\n" +
+        "Aa87gw0DyvGFG8Vy9POWT9sRP1/JAkBqP0hrMvYMSs6+MSn0eHo2151PsAJIQcuO\n" +
+        "U2/Da1khSzu8N6WMi2GiobgV/RYRbf9KrY2ZzMZjykZQYOxAjopBAkEAghCu38cN\n" +
+        "aOsW6ueo24uzsWI1FTdE+qWNVEi3RSP120xXBCyhaBjIq4WVSlJK9K2aBaJpit3j\n" +
+        "iQ5tl6zrLlxQhg==";
+
+    // Certificate information:
+    // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=casigner
+    // Validity
+    //     Not Before: May  5 02:40:57 2012 GMT
+    //     Not After : Jan 21 02:40:57 2032 GMT
+    // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer
+    // X509v3 Subject Key Identifier:
+    //     39:0E:C6:33:B1:50:BC:73:07:31:E5:D8:04:F7:BB:97:55:CF:9B:C8
+    // X509v3 Authority Key Identifier:
+    //     keyid:13:07:E0:11:07:DB:EB:33:23:87:31:D0:DB:7E:16:56:BE:11:90:0A
+    //     DirName:/C=US/O=Java/OU=SunJSSE Test Serivce
+    //     serial:02
+    static String certIssuerStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICvjCCAiegAwIBAgIBAzANBgkqhkiG9w0BAQQFADBOMQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxETAP\n" +
+        "BgNVBAMTCGNhc2lnbmVyMB4XDTEyMDUwNTAyNDA1N1oXDTMyMDEyMTAyNDA1N1ow\n" +
+        "UDELMAkGA1UEBhMCVVMxDTALBgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0Ug\n" +
+        "VGVzdCBTZXJpdmNlMRMwEQYDVQQDEwpjZXJ0aXNzdWVyMIGfMA0GCSqGSIb3DQEB\n" +
+        "AQUAA4GNADCBiQKBgQCyz55zinU6kNL/LeiTNiBI0QWYmDG0YTotuC4D75liBNqs\n" +
+        "7Mmladsh2mTtQUAwmuGaGzaZV25a+cUax0DXZoyBwdbTI09u1bUYsZcaUUKbPoCC\n" +
+        "HH26e4jLFL4olW13Sv4ZAd57tIYevMw+Fp5f4fLPFGegCJTFlv2Qjpmic/cuvQID\n" +
+        "AQABo4GpMIGmMB0GA1UdDgQWBBQ5DsYzsVC8cwcx5dgE97uXVc+byDBjBgNVHSME\n" +
+        "XDBagBQTB+ARB9vrMyOHMdDbfhZWvhGQCqE/pD0wOzELMAkGA1UEBhMCVVMxDTAL\n" +
+        "BgNVBAoTBEphdmExHTAbBgNVBAsTFFN1bkpTU0UgVGVzdCBTZXJpdmNlggECMBMG\n" +
+        "A1UdEwEB/wQJMAcBAf8CAgQAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQQFAAOB\n" +
+        "gQCQTagenCdClT98C+oTJGJrw/dUBD9K3tE6ZJKPMc/2bUia8G5ei1C0eXj4mWG2\n" +
+        "lu9umR6C90/A6qB050QB2h50qtqxSrkpu+ym1yypauZpg7U3nUY9wZWJNI1vqrQZ\n" +
+        "pqUMRcXY3iQIVKx+Qj+4/Za1wwFQzpEoGmqRW31V1SdMEw==\n" +
+        "-----END CERTIFICATE-----";
+    static String certIssuerPrivateKey = // Private key in the format of PKCS#8
+        "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBALLPnnOKdTqQ0v8t\n" +
+        "6JM2IEjRBZiYMbRhOi24LgPvmWIE2qzsyaVp2yHaZO1BQDCa4ZobNplXblr5xRrH\n" +
+        "QNdmjIHB1tMjT27VtRixlxpRQps+gIIcfbp7iMsUviiVbXdK/hkB3nu0hh68zD4W\n" +
+        "nl/h8s8UZ6AIlMWW/ZCOmaJz9y69AgMBAAECgYEAjtew2tgm4gxDojqIauF4VPM1\n" +
+        "pzsdqd1p3pAdomNLgrQiBLZ8N7oiph6TNb1EjA+OXc+ThFgF/oM9ZDD8qZZwcvjN\n" +
+        "qDZlpTkFs2TaGcyEZfUaMB45NHVs6Nn+pSkagSNwwy3xeyAct7sQEzGNTDlEwVv5\n" +
+        "7V9LQutQtBd6xT48KzkCQQDpNRfv2OFNG/6GtzJoO68oJhpnpl2MsYNi4ntRkre/\n" +
+        "6uXpiCYaDskcrPMRwOOs0m7mxG+Ev+uKnLnSoEMm1GCbAkEAxEmDtiD0Psb8Z9BL\n" +
+        "ZRb83Jqho3xe2MCAh3xUfz9b/Mhae9dZ44o4OCgQZuwvW1mczF0NtpgZl93BmYa2\n" +
+        "hTwHhwJBAKHrEj6ep/fA6x0gD2idoATRR94VfbiU+7NpqtO9ecVP0+gsdr/66hn1\n" +
+        "3yLBeZLh3MxvMTrLgkAQh1i9m0JXjOcCQQClLXAHHegrw+u3uNMZeKTFR+Lp3sk6\n" +
+        "AZSnbvr0Me9I45kxSeG81x3ENALJecvIRbrrRws5MvmmkNhQR8rkh8WVAkEAk6b+\n" +
+        "aVtmBgUaTS5+FFlHGHJY9HFrfT1a1C/dwyMuqlmbC3YsBmZaMOlKli5TXNybLff8\n" +
+        "5KMeGEpXMzgC7AscGA==";
+
+    // Certificate information:
+    // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer
+    // Validity
+    //     Not Before: May  5 02:41:01 2012 GMT
+    //     Not After : Jan 21 02:41:01 2032 GMT
+    // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=localhost
+    // X509v3 Subject Key Identifier:
+    //     AD:C0:2C:4C:E4:C2:2E:A1:BB:5D:92:BE:66:E0:4E:E0:0D:2F:11:EF
+    // X509v3 Authority Key Identifier:
+    //     keyid:39:0E:C6:33:B1:50:BC:73:07:31:E5:D8:04:F7:BB:97:55:CF:9B:C8
+    static String serverCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICjTCCAfagAwIBAgIBBDANBgkqhkiG9w0BAQQFADBQMQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEzAR\n" +
+        "BgNVBAMTCmNlcnRpc3N1ZXIwHhcNMTIwNTA1MDI0MTAxWhcNMzIwMTIxMDI0MTAx\n" +
+        "WjBPMQswCQYDVQQGEwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNT\n" +
+        "RSBUZXN0IFNlcml2Y2UxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0B\n" +
+        "AQEFAAOBjQAwgYkCgYEAvwaUd7wmBSKqycEstYLWD26vkU08DM39EtaT8wL9HnQ0\n" +
+        "fgPblwBFI4zdLa2cuYXRZcFUb04N8nrkcpR0D6kkE+AlFAoRWrrZF80B7JTbtEK4\n" +
+        "1PIeurihXvUT+4MpzGLOojIihMfvM4ufelblD56SInso4WFHm7t4qCln88J1gjkC\n" +
+        "AwEAAaN4MHYwCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBStwCxM5MIuobtdkr5m4E7g\n" +
+        "DS8R7zAfBgNVHSMEGDAWgBQ5DsYzsVC8cwcx5dgE97uXVc+byDAnBgNVHSUEIDAe\n" +
+        "BggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDMA0GCSqGSIb3DQEBBAUAA4GB\n" +
+        "AGfwcfdvEG/nSCiAn2MGbYHp34mgF3OA1SJLWUW0LvWJhwm2cn4AXlSoyvbwrkaB\n" +
+        "IDDCwhJvvc0vUyL2kTx7sqVaFTq3mDs+ktlB/FfH0Pb+i8FE+g+7T42Iw/j0qxHL\n" +
+        "YmgbrjBQf5WYN1AvBE/rrPt9aOtS3UsqtVGW574b0shW\n" +
+        "-----END CERTIFICATE-----";
+    static String serverPrivateKey = // Private key in the format of PKCS#8
+        "MIICdAIBADANBgkqhkiG9w0BAQEFAASCAl4wggJaAgEAAoGBAL8GlHe8JgUiqsnB\n" +
+        "LLWC1g9ur5FNPAzN/RLWk/MC/R50NH4D25cARSOM3S2tnLmF0WXBVG9ODfJ65HKU\n" +
+        "dA+pJBPgJRQKEVq62RfNAeyU27RCuNTyHrq4oV71E/uDKcxizqIyIoTH7zOLn3pW\n" +
+        "5Q+ekiJ7KOFhR5u7eKgpZ/PCdYI5AgMBAAECf3CscOYvFD3zNMnMJ5LomVqA7w3F\n" +
+        "gKYM2jlCWAH+wU41PMEXhW6Lujw92jgXL1o+lERwxFzirVdZJWZwKgUSvzP1G0h3\n" +
+        "fkucq1/UWnToK+8NSXNM/yS8hXbBgSEoJo5f7LKcIi1Ev6doBVofMxs+njzyWKbM\n" +
+        "Nb7rOLHadghoon0CQQDgQzbzzSN8Dc1YmmylhI5v+0sQRHH0DL7D24k4Weh4vInG\n" +
+        "EAbt4x8M7ZKEo8/dv0s4hbmNmAnJl93/RRxIyEqLAkEA2g87DiswSQam2pZ8GlrO\n" +
+        "+w4Qg9mH8uxx8ou2rl0XlHzH1XiTNbkjfY0EZoL7L31BHFk9n11Fb2P85g6ws+Hy\n" +
+        "ywJAM/xgyLNM/nzUlS128geAXUULaYH0SHaL4isJ7B4rXZGW/mrIsGxtzjlkNYsj\n" +
+        "rGujrD6TfNc5rZmexIXowJZtcQJBAIww+pCzZ4mrgx5JXWQ8OZHiiu+ZrPOa2+9J\n" +
+        "r5sOMpi+WGN/73S8oHqZbNjTINZ5OqEVJq8MchWZPQBTNXuQql0CQHEjUzzkCQa3\n" +
+        "j6JTa2KAdqyvLOx0XF9zcc1gA069uNQI2gPUHS8V215z57f/gMGnDNhVfLs/vMKz\n" +
+        "sFkVZ3zg7As=";
+
+    // Certificate information:
+    // Issuer: C=US, O=Java, OU=SunJSSE Test Serivce, CN=certissuer
+    // Validity
+    //     Not Before: May  5 02:41:02 2012 GMT
+    //     Not After : Jan 21 02:41:02 2032 GMT
+    // Subject: C=US, O=Java, OU=SunJSSE Test Serivce, CN=InterOp Tester
+    // X509v3 Subject Key Identifier:
+    //     57:7D:E2:33:33:60:DF:DD:5E:ED:81:3F:EB:F2:1B:59:7F:50:9C:99
+    // X509v3 Authority Key Identifier:
+    //     keyid:39:0E:C6:33:B1:50:BC:73:07:31:E5:D8:04:F7:BB:97:55:CF:9B:C8
+    static String clientCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICaTCCAdKgAwIBAgIBBTANBgkqhkiG9w0BAQQFADBQMQswCQYDVQQGEwJVUzEN\n" +
+        "MAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2UxEzAR\n" +
+        "BgNVBAMTCmNlcnRpc3N1ZXIwHhcNMTIwNTA1MDI0MTAyWhcNMzIwMTIxMDI0MTAy\n" +
+        "WjBUMQswCQYDVQQGEwJVUzENMAsGA1UEChMESmF2YTEdMBsGA1UECxMUU3VuSlNT\n" +
+        "RSBUZXN0IFNlcml2Y2UxFzAVBgNVBAMTDkludGVyT3AgVGVzdGVyMIGfMA0GCSqG\n" +
+        "SIb3DQEBAQUAA4GNADCBiQKBgQC1pA71nDg1KhhnHjRdi/eVDUa7uFZAtN8R9huu\n" +
+        "pTwFoyqSX8lDMz8jDawOMmaI9dVZLjTh3hnf4KBEqQOearFVz45yBOjlgPLBuI4F\n" +
+        "D/ORhgmDaIu2NK+c1yj6YQlyiO0DPwh55GtPLVG3iuEpejU7gQyaMuTaddoXrO7s\n" +
+        "xwzanQIDAQABo08wTTALBgNVHQ8EBAMCA+gwHQYDVR0OBBYEFFd94jMzYN/dXu2B\n" +
+        "P+vyG1l/UJyZMB8GA1UdIwQYMBaAFDkOxjOxULxzBzHl2AT3u5dVz5vIMA0GCSqG\n" +
+        "SIb3DQEBBAUAA4GBAHTgB5W7wnl7Jnb4wNQcb6JdR8FRHIdslcRfnReFfZBHZZux\n" +
+        "ChpA1lf62KIzYohKoxQXXMul86vnVSHnXq5xctHEmxCBnALEnoAcCOv6wfWqEA7g\n" +
+        "2rX+ydmu+0ArbqKhSOypZ7K3ame0UOJJ6HDxdsgBYJuotmSou4KKq9e8GF+d\n" +
+        "-----END CERTIFICATE-----";
+    static String clientPrivateKey = // Private key in the format of PKCS#8
+        "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALWkDvWcODUqGGce\n" +
+        "NF2L95UNRru4VkC03xH2G66lPAWjKpJfyUMzPyMNrA4yZoj11VkuNOHeGd/goESp\n" +
+        "A55qsVXPjnIE6OWA8sG4jgUP85GGCYNoi7Y0r5zXKPphCXKI7QM/CHnka08tUbeK\n" +
+        "4Sl6NTuBDJoy5Np12hes7uzHDNqdAgMBAAECgYEAjLwygwapXjfhdHQoqpp6F9iT\n" +
+        "h3sKCVSaybXgOO75lHyZzZO9wv1/288KEm3mmBOxXEm6245UievnAYvaq/GKt93O\n" +
+        "pj2zRefBzZjGbz0v84fmna/MN6zUUYX1PcVRMKWLx9HKKmQihzwoXdBX0o9PPXdi\n" +
+        "LfzujNa/q8/mpI5PmEECQQDZwLSaL7OReWZTY4NoQuNzwhx5IKJUOtCFQfmHKZSW\n" +
+        "wtXntZf+E5W9tGaDY5wjpq5cilKDAHdEAlFWxDe1PoE1AkEA1YuTBpctOLBfquFn\n" +
+        "Y/S3lzGVlnIHDk3dj4bFglkoJ2bCdlwRNUyBSjAjBDcbYhper8S7GlEN5SiEdz9I\n" +
+        "3OjIyQJBAKEPMgYhZjYhjxf6sQV7A/VpC9pj0u1uGzGVXNUmYisorUKXRHa/UbBh\n" +
+        "MLnaAXE1Jh54iRMwUwbQmA0PUQ0T0EkCQQCcr6/umwhkWw2nHYK2Vf5LoudGn15M\n" +
+        "AZg7UsEjVnXfC0hOfllmCT+ohs96rVCbWAv33lsHAUg3x9YChV3aMbf5AkAj1kuV\n" +
+        "jUTgFKjediyQC6uof7YdLn+gQGiXK1XE0GBN4WMkzcLiS0jC+MFTgKfFnFdh9K0y\n" +
+        "fswYKdTA/o8RKaa5";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = getSSLContext(true);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+        SSLSocket sslSocket = null;
+        try {
+            /*
+             * Signal Client, we're ready for his connect.
+             */
+            serverReady = true;
+
+            sslSocket = (SSLSocket) sslServerSocket.accept();
+            sslSocket.setNeedClientAuth(true);
+
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+        } finally {
+            if (sslSocket != null) {
+                sslSocket.close();
+            }
+            sslServerSocket.close();
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = getSSLContext(false);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" });
+        try {
+            InputStream sslIS = sslSocket.getInputStream();
+            OutputStream sslOS = sslSocket.getOutputStream();
+
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    // get the ssl context
+    private static SSLContext getSSLContext(boolean isServer) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        ByteArrayInputStream is =
+            new ByteArrayInputStream(trusedCertStr.getBytes());
+        Certificate trusedCert = cf.generateCertificate(is);
+        is.close();
+
+        ks.setCertificateEntry("SunJSSE Test Serivce", trusedCert);
+
+        // import the certificate chain and key
+        Certificate[] chain = new Certificate[3];
+
+        is = new ByteArrayInputStream(caSignerStr.getBytes());
+        Certificate caSignerCert = cf.generateCertificate(is);
+        is.close();
+        chain[2] = caSignerCert;
+
+        is = new ByteArrayInputStream(certIssuerStr.getBytes());
+        Certificate certIssuerCert = cf.generateCertificate(is);
+        is.close();
+        chain[1] = certIssuerCert;
+
+        PKCS8EncodedKeySpec priKeySpec = null;
+        if (isServer) {
+            priKeySpec = new PKCS8EncodedKeySpec(
+                            Base64.getMimeDecoder().decode(serverPrivateKey));
+            is = new ByteArrayInputStream(serverCertStr.getBytes());
+        } else {
+            priKeySpec = new PKCS8EncodedKeySpec(
+                            Base64.getMimeDecoder().decode(clientPrivateKey));
+            is = new ByteArrayInputStream(clientCertStr.getBytes());
+        }
+        KeyFactory kf = KeyFactory.getInstance("RSA");
+        RSAPrivateKey priKey = (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+        Certificate keyCert = cf.generateCertificate(is);
+        is.close();
+        chain[0] = keyCert;
+
+        ks.setKeyEntry("End Entity", priKey, passphrase, chain);
+
+        // check the certification path
+        PKIXParameters paras = new PKIXParameters(ks);
+        paras.setRevocationEnabled(false);
+        CertPath path = cf.generateCertPath(Arrays.asList(chain));
+        CertPathValidator cv = CertPathValidator.getInstance("PKIX");
+        cv.validate(path, paras);
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+        kmf.init(ks, passphrase);
+
+        ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+        ks = null;
+
+        return ctx;
+    }
+
+    private static String tmAlgorithm;        // trust manager
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String args[]) throws Exception {
+        // MD5 is used in this test case, don't disable MD5 algorithm.
+        Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "MD2, RSA keySize < 1024");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new BasicConstraints();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    BasicConstraints() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null)
+            throw serverException;
+        if (clientException != null)
+            throw clientException;
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/X509TrustManagerImpl/CertRequestOverflow.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2012, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 7200295
+ * @summary CertificateRequest message is wrapping when using large
+ *          numbers of Certs
+ * @run main/othervm CertRequestOverflow
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.net.ssl.*;
+import java.security.cert.*;
+import java.security.*;
+
+public class CertRequestOverflow {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+    private final static char[] cpasswd = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+                                getContext(true).getServerSocketFactory();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+        if (debug) {
+            System.out.println("Server port is " + serverPort);
+        }
+
+        // enable endpoint identification
+        // ignore, we may test the feature when known how to parse client
+        // hostname
+        //SSLParameters params = sslServerSocket.getSSLParameters();
+        //params.setEndpointIdentificationAlgorithm("HTTPS");
+        //sslServerSocket.setSSLParameters(params);
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.setNeedClientAuth(true);
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        try {
+            sslIS.read();
+            sslOS.write(85);
+            sslOS.flush();
+
+            throw new Exception("SERVER TEST FAILED!  " +
+                        "It is expected to fail with field length overflow");
+        } catch (SSLException ssle) {
+            Throwable cause = ssle.getCause();
+            if (!(cause instanceof RuntimeException)) {
+                System.out.println("We are expecting a RuntimeException!");
+                throw ssle;
+            }
+            System.out.println("The expected exception!  " + ssle);
+        } finally {
+            sslSocket.close();
+        }
+
+        System.out.println("SERVER TEST PASSED!");
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf = getContext(false).getSocketFactory();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+        if (debug) {
+            System.out.println("Connected to: " +
+                    sslSocket.getRemoteSocketAddress());
+        }
+
+        // enable endpoint identification
+        SSLParameters params = sslSocket.getSSLParameters();
+        params.setEndpointIdentificationAlgorithm("HTTPS");
+        sslSocket.setSSLParameters(params);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        try {
+            sslOS.write(280);
+            sslOS.flush();
+            sslIS.read();
+        } catch (SSLException ssle) {
+            System.out.println("An expected exception!");
+        } finally {
+            sslSocket.close();
+        }
+    }
+
+    MyExtendedX509TM serverTM;
+    MyExtendedX509TM clientTM;
+
+    private SSLContext getContext(boolean server) throws Exception {
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(new FileInputStream(keyFilename), cpasswd);
+        kmf.init(ks, cpasswd);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        KeyStore ts = KeyStore.getInstance("JKS");
+        ts.load(new FileInputStream(trustFilename), cpasswd);
+        tmf.init(ts);
+
+        TrustManager tms[] = tmf.getTrustManagers();
+        if (tms == null || tms.length == 0) {
+            throw new Exception("unexpected trust manager implementation");
+        } else {
+           if (!(tms[0] instanceof X509TrustManager)) {
+            throw new Exception("unexpected trust manager implementation: "
+                                + tms[0].getClass().getCanonicalName());
+           }
+        }
+
+        if (server) {
+            serverTM = new MyExtendedX509TM((X509TrustManager)tms[0]);
+
+            tms = new TrustManager[] {serverTM};
+        } else {
+            clientTM = new MyExtendedX509TM((X509TrustManager)tms[0]);
+
+            tms = new TrustManager[] {clientTM};
+        }
+
+        SSLContext ctx = SSLContext.getInstance("TLSv1.2");
+        ctx.init(kmf.getKeyManagers(), tms, null);
+
+        return ctx;
+    }
+
+    static class MyExtendedX509TM extends X509ExtendedTrustManager
+            implements X509TrustManager {
+
+        X509TrustManager tm;
+
+        boolean clientChecked;
+        boolean serverChecked;
+
+        MyExtendedX509TM(X509TrustManager tm) {
+            clientChecked = false;
+            serverChecked = false;
+
+            this.tm = tm;
+        }
+
+        public boolean wasClientChecked() {
+            return clientChecked;
+        }
+
+        public boolean wasServerChecked() {
+            return serverChecked;
+        }
+
+        @Override
+        public void checkClientTrusted(X509Certificate chain[], String authType)
+                throws CertificateException {
+            tm.checkClientTrusted(chain, authType);
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate chain[], String authType)
+                throws CertificateException {
+            tm.checkServerTrusted(chain, authType);
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+            // (hack code) increase the size of the returned array to make a
+            // overflow CertificateRequest.
+            List<X509Certificate> issuersList = new LinkedList<>();
+            X509Certificate[] issuers = tm.getAcceptedIssuers();
+            for (int i = 0; i < 800; i += issuers.length) {
+                for (X509Certificate issuer : issuers) {
+                    issuersList.add(issuer);
+                }
+            }
+
+            return issuersList.toArray(issuers);
+        }
+
+        @Override
+        public void checkClientTrusted(X509Certificate[] chain, String authType,
+                Socket socket) throws CertificateException {
+            clientChecked = true;
+            tm.checkClientTrusted(chain, authType);
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] chain, String authType,
+                Socket socket) throws CertificateException {
+            serverChecked = true;
+            tm.checkServerTrusted(chain, authType);
+        }
+
+        @Override
+        public void checkClientTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+            clientChecked = true;
+            tm.checkClientTrusted(chain, authType);
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] chain, String authType,
+            SSLEngine engine) throws CertificateException {
+            serverChecked = true;
+            tm.checkServerTrusted(chain, authType);
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new CertRequestOverflow();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    CertRequestOverflow() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null)
+            throw serverException;
+        if (clientException != null)
+            throw clientException;
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                @Override
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+              * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/X509TrustManagerImpl/ClientServer.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2002, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 4717766
+ * @author Brad Wetmore
+ * @summary 1.0.3 JsseX509TrustManager erroneously calls isClientTrusted()
+ * @modules java.base/com.sun.net.ssl
+ * @run main/manual ClientServer
+ */
+
+/*
+ * SunJSSE does not support dynamic system properties, no way to re-use
+ * system properties in samevm/agentvm mode.
+ *
+ * JSSE supports algorithm constraints with CR 6916074, need to update
+ * this test case in JDK 7 soon.
+ *
+ * This problem didn't exist in JSSE 1.4, only JSSE 1.0.3.  However,
+ * this is a useful test, so I decided to include it in 1.4.2.
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.security.cert.*;
+import java.security.*;
+import com.sun.net.ssl.*;
+
+public class ClientServer {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../javax/net/ssl/etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf = getDefaultServer();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.setNeedClientAuth(true);
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+
+        sslSocket.close();
+
+        if (!serverTM.wasServerChecked() && serverTM.wasClientChecked()) {
+            System.out.println("SERVER TEST PASSED!");
+        } else {
+            throw new Exception("SERVER TEST FAILED!  " +
+                !serverTM.wasServerChecked() + " " +
+                serverTM.wasClientChecked());
+        }
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf = getDefaultClient();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+
+        if (clientTM.wasServerChecked() && !clientTM.wasClientChecked()) {
+            System.out.println("CLIENT TEST PASSED!");
+        } else {
+            throw new Exception("CLIENT TEST FAILED!  " +
+                clientTM.wasServerChecked() + " " +
+                !clientTM.wasClientChecked());
+        }
+    }
+
+    private com.sun.net.ssl.SSLContext getDefault(MyX509TM tm)
+            throws Exception {
+
+        String keyFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", "./") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        char[] passphrase = "passphrase".toCharArray();
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(new FileInputStream(keyFilename), passphrase);
+
+        com.sun.net.ssl.KeyManagerFactory kmf =
+            com.sun.net.ssl.KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        ks = KeyStore.getInstance("JKS");
+        ks.load(new FileInputStream(trustFilename), passphrase);
+
+        com.sun.net.ssl.TrustManagerFactory tmf =
+            com.sun.net.ssl.TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ks);
+
+        com.sun.net.ssl.TrustManager [] tms = tmf.getTrustManagers();
+
+        int i;
+        for (i = 0; i < tms.length; i++) {
+            if (tms[i] instanceof com.sun.net.ssl.X509TrustManager) {
+                break;
+            }
+        }
+
+        if (i >= tms.length) {
+            throw new Exception("Couldn't find X509TM");
+        }
+
+        tm.init((com.sun.net.ssl.X509TrustManager)tms[i]);
+        tms = new MyX509TM [] { tm };
+
+        com.sun.net.ssl.SSLContext ctx =
+            com.sun.net.ssl.SSLContext.getInstance("TLS");
+        ctx.init(kmf.getKeyManagers(), tms, null);
+        return ctx;
+    }
+
+    MyX509TM serverTM;
+    MyX509TM clientTM;
+
+    private SSLServerSocketFactory getDefaultServer() throws Exception {
+        serverTM = new MyX509TM();
+        return getDefault(serverTM).getServerSocketFactory();
+    }
+
+    private SSLSocketFactory getDefaultClient() throws Exception {
+        clientTM = new MyX509TM();
+        return getDefault(clientTM).getSocketFactory();
+    }
+
+    static class MyX509TM implements com.sun.net.ssl.X509TrustManager {
+
+        com.sun.net.ssl.X509TrustManager tm;
+        boolean clientChecked;
+        boolean serverChecked;
+
+        void init(com.sun.net.ssl.X509TrustManager x509TM) {
+            tm = x509TM;
+        }
+
+        public boolean wasClientChecked() {
+            return clientChecked;
+        }
+
+        public boolean wasServerChecked() {
+            return serverChecked;
+        }
+
+        public boolean isClientTrusted(X509Certificate[] chain) {
+            clientChecked = true;
+            return true;
+        }
+
+        public boolean isServerTrusted(X509Certificate[] chain) {
+            serverChecked = true;
+            return true;
+        }
+
+        public X509Certificate[] getAcceptedIssuers() {
+            return tm.getAcceptedIssuers();
+        }
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new ClientServer();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    ClientServer() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null)
+            throw serverException;
+        if (clientException != null)
+            throw clientException;
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/X509TrustManagerImpl/SelfIssuedCert.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,413 @@
+/*
+ * Copyright (c) 2009, 2018, 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.
+ *
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 6822460
+ * @summary support self-issued certificate
+ * @run main/othervm SelfIssuedCert PKIX
+ * @run main/othervm SelfIssuedCert SunX509
+ * @author Xuelei Fan
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.math.BigInteger;
+
+import java.util.Base64;
+
+public class SelfIssuedCert {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = true;
+
+    /*
+     * Where do we find the keystores?
+     */
+    // Certificate information:
+    // Issuer: C=US, O=Example, CN=localhost
+    // Validity
+    //     Not Before: May 25 00:35:58 2009 GMT
+    //     Not After : May  5 00:35:58 2030 GMT
+    // Subject: C=US, O=Example, CN=localhost
+    // X509v3 Subject Key Identifier:
+    //     56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
+    // X509v3 Authority Key Identifier:
+    //     keyid:56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
+    //     DirName:/C=US/O=Example/CN=localhost
+    //     serial:00
+    static String trusedCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICejCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQQFADAzMQswCQYDVQQGEwJVUzEQ\n" +
+        "MA4GA1UEChMHRXhhbXBsZTESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTA5MDUyNTAw\n" +
+        "MDQ0M1oXDTMwMDUwNTAwMDQ0M1owMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4\n" +
+        "YW1wbGUxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
+        "gYkCgYEA0Wvh3FHYGQ3vvw59yTjUxT6QuY0fzwCGQTM9evXr/V9+pjWmaTkNDW+7\n" +
+        "S/LErlWz64gOWTgcMZN162sVgx4ct/q27brY+SlUO5eSud1fSac6SfefhOPBa965\n" +
+        "Xc4mnpDt5sgQPMDCuFK7Le6A+/S9J42BO2WYmNcmvcwWWrv+ehcCAwEAAaOBnTCB\n" +
+        "mjAdBgNVHQ4EFgQUq3q5fYEibdvLpab+JY4pmifj2vYwWwYDVR0jBFQwUoAUq3q5\n" +
+        "fYEibdvLpab+JY4pmifj2vahN6Q1MDMxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdF\n" +
+        "eGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAwDwYDVR0TAQH/BAUwAwEB/zAL\n" +
+        "BgNVHQ8EBAMCAgQwDQYJKoZIhvcNAQEEBQADgYEAHL8BSwtX6s8WPPG2FbQBX+K8\n" +
+        "GquAyQNtgfJNm60B4i+fVBkJiQJtLmE0emvHx/3sIaHmB0Gd0HKnk/cIQXY304vr\n" +
+        "QpqwudKcIZuzmj+pa7807joV+WzRDVIlt4HpYg7tiUvEoyw+X8jwY2lgiGR7mWu6\n" +
+        "jQU8PN/06+qgtvSGFpo=\n" +
+        "-----END CERTIFICATE-----";
+
+    // Certificate information:
+    // Issuer: C=US, O=Example, CN=localhost
+    // Validity
+    //     Not Before: May 25 00:35:58 2009 GMT
+    //     Not After : May  5 00:35:58 2030 GMT
+    // Subject: C=US, O=Example, CN=localhost
+    // X509v3 Subject Key Identifier:
+    //     0D:30:76:22:D6:9D:75:EF:FD:83:50:31:18:08:83:CD:01:4E:6A:C4
+    // X509v3 Authority Key Identifier:
+    //     keyid:56:AB:FE:15:4C:9C:4A:70:90:DC:0B:9B:EB:BE:DC:03:CC:7F:CE:CF
+    //     DirName:/C=US/O=Example/CN=localhost
+    //     serial:00
+    static String targetCertStr =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIICaTCCAdKgAwIBAgIBAjANBgkqhkiG9w0BAQQFADAzMQswCQYDVQQGEwJVUzEQ\n" +
+        "MA4GA1UEChMHRXhhbXBsZTESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTA5MDUyNTAw\n" +
+        "MDQ0M1oXDTI5MDIwOTAwMDQ0M1owMzELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0V4\n" +
+        "YW1wbGUxEjAQBgNVBAMTCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw\n" +
+        "gYkCgYEAzmPahrH9LTQv3HEWsua+hIpzyU1ACooSd5BtDjc7XnVzSdGW8QD9R8EA\n" +
+        "xko7TvfJo6IH6wwgHBspySwsl+6xvHhbwQjgtWlT71ksrUbqcUzmvSvcycQYA8RC\n" +
+        "yk9HK5pEJQgSxldpR3Kmy0V6CHC4dCm15trnJYWisTuezY3fjXECAwEAAaOBjDCB\n" +
+        "iTAdBgNVHQ4EFgQUQkiWFRkjKsfwFo7UMQfGEzNNW60wWwYDVR0jBFQwUoAUq3q5\n" +
+        "fYEibdvLpab+JY4pmifj2vahN6Q1MDMxCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdF\n" +
+        "eGFtcGxlMRIwEAYDVQQDEwlsb2NhbGhvc3SCAQAwCwYDVR0PBAQDAgPoMA0GCSqG\n" +
+        "SIb3DQEBBAUAA4GBAIMz7c1R+6KEO7FmH4rnv9XE62xkg03ff0vKXLZMjjs0CX2z\n" +
+        "ybRttuTFafHA6/JS+Wz0G83FCRVeiw2WPU6BweMwwejzzIrQ/K6mbp6w6sRFcbNa\n" +
+        "eLBtzkjEtI/htOSSq3/0mbKmWn5uVJckO4QiB8kUR4F7ngM9l1uuI46ZfUsk\n" +
+        "-----END CERTIFICATE-----";
+
+    // Private key in the format of PKCS#8
+    static String targetPrivateKey =
+        "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAM5j2oax/S00L9xx\n" +
+        "FrLmvoSKc8lNQAqKEneQbQ43O151c0nRlvEA/UfBAMZKO073yaOiB+sMIBwbKcks\n" +
+        "LJfusbx4W8EI4LVpU+9ZLK1G6nFM5r0r3MnEGAPEQspPRyuaRCUIEsZXaUdypstF\n" +
+        "eghwuHQpteba5yWForE7ns2N341xAgMBAAECgYEAgZ8k98OBhopoJMLBxso0jXmH\n" +
+        "Dr59oiDlSEJku7DkkIajSZFggyxj5lTI78BfT1FASozQ/EY5RG2q6LXdq+41oU/U\n" +
+        "JVEQWhdIE1mQDwE0vgaYdjzMaVIsC3cZYOCOmCYvNxCiTt7e/z8yBMmAE5udqJMB\n" +
+        "pim4WXDfpy0ssK81oCECQQDwMC4xu+kn0yD/Qyi9Zn26gIRDv4bjzDQoJfSvMhrY\n" +
+        "a4duxLzh9u4gCDd0+wHxpPQvNxGCk0c1JUxBJ2rb4G3HAkEA2/oVRV6+xiRXUnoo\n" +
+        "bdPEO27zEJmdpE42yU/JLIy6DPu2IUhEqY45fU2ZERmwMdhpiK/vsf/CZKJ2j/ZU\n" +
+        "PdMLBwJBAJIYTFDWAqjFpCGAASzLRZiGiW0H941h7Suqgp159ZhEN5mps1Yis47q\n" +
+        "UIkoEHOiKSD69vychsiNykcrKbVaWosCQQC1UrYX4Vo1r5z/EkyjAwzcxL68rzM/\n" +
+        "TW1hkU/NVg7CRvXBB3X5oY+H1t/WNauD2tRa5FMbESwmkbhTQIP+FikfAkEA4goD\n" +
+        "HCxUn0Z1OQq9QL6y1Yoof6sHxicUwABosuCLJnDJmA5vhpemvdXQTzFII8g1hyQf\n" +
+        "z1yyDoxhddcleKlJvQ==";
+
+    static char passphrase[] = "passphrase".toCharArray();
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLContext context = getSSLContext(null, targetCertStr,
+                                            targetPrivateKey);
+        SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket)sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        sslSocket.setNeedClientAuth(false);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+
+        sslSocket.close();
+
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLContext context = getSSLContext(trusedCertStr, null, null);
+        SSLSocketFactory sslsf = context.getSocketFactory();
+
+        SSLSocket sslSocket =
+            (SSLSocket)sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledProtocols(new String[] { "TLSv1", "TLSv1.1", "TLSv1.2" });
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+    }
+
+    // get the ssl context
+    private static SSLContext getSSLContext(String trusedCertStr,
+            String keyCertStr, String keySpecStr) throws Exception {
+
+        // generate certificate from cert string
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+        // create a key store
+        KeyStore ks = KeyStore.getInstance("JKS");
+        ks.load(null, null);
+
+        // import the trused cert
+        Certificate trusedCert = null;
+        ByteArrayInputStream is = null;
+        if (trusedCertStr != null) {
+            is = new ByteArrayInputStream(trusedCertStr.getBytes());
+            trusedCert = cf.generateCertificate(is);
+            is.close();
+
+            ks.setCertificateEntry("RSA Export Signer", trusedCert);
+        }
+
+        if (keyCertStr != null) {
+            // generate the private key.
+            PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+                                Base64.getMimeDecoder().decode(keySpecStr));
+            KeyFactory kf = KeyFactory.getInstance("RSA");
+            RSAPrivateKey priKey =
+                    (RSAPrivateKey)kf.generatePrivate(priKeySpec);
+
+            // generate certificate chain
+            is = new ByteArrayInputStream(keyCertStr.getBytes());
+            Certificate keyCert = cf.generateCertificate(is);
+            is.close();
+
+            Certificate[] chain = null;
+            if (trusedCert != null) {
+                chain = new Certificate[2];
+                chain[0] = keyCert;
+                chain[1] = trusedCert;
+            } else {
+                chain = new Certificate[1];
+                chain[0] = keyCert;
+            }
+
+            // import the key entry.
+            ks.setKeyEntry("Whatever", priKey, passphrase, chain);
+        }
+
+        // create SSL context
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+        tmf.init(ks);
+
+        SSLContext ctx = SSLContext.getInstance("TLS");
+        if (keyCertStr != null && !keyCertStr.isEmpty()) {
+            KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+            kmf.init(ks, passphrase);
+
+            ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+            ks = null;
+        } else {
+            ctx.init(null, tmf.getTrustManagers(), null);
+        }
+
+        return ctx;
+    }
+
+    private static String tmAlgorithm;        // trust manager
+
+    private static void parseArguments(String[] args) {
+        tmAlgorithm = args[0];
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String args[]) throws Exception {
+        // MD5 is used in this test case, don't disable MD5 algorithm.
+        Security.setProperty("jdk.certpath.disabledAlgorithms",
+                "MD2, RSA keySize < 1024");
+        Security.setProperty("jdk.tls.disabledAlgorithms",
+                "SSLv3, RC4, DH keySize < 768");
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+
+        /*
+         * Get the customized arguments.
+         */
+        parseArguments(args);
+
+        /*
+         * Start the tests.
+         */
+        new SelfIssuedCert();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    SelfIssuedCert() throws Exception {
+        if (separateServerThread) {
+            startServer(true);
+            startClient(false);
+        } else {
+            startClient(true);
+            startServer(false);
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            serverThread.join();
+        } else {
+            clientThread.join();
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         *
+         * If the main thread excepted, that propagates back
+         * immediately.  If the other thread threw an exception, we
+         * should report back.
+         */
+        if (serverException != null)
+            throw serverException;
+        if (clientException != null)
+            throw clientException;
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            doServerSide();
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            doClientSide();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/X509TrustManagerImpl/Symantec/Distrust.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2018, 2019, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.cert.*;
+import java.time.*;
+import java.util.*;
+import javax.net.ssl.*;
+import sun.security.validator.Validator;
+import sun.security.validator.ValidatorException;
+
+import jdk.test.lib.security.SecurityUtils;
+
+/**
+ * @test
+ * @bug 8207258 8216280
+ * @summary Check that TLS Server certificates chaining back to distrusted
+ *          Symantec roots are invalid
+ * @library /test/lib
+ * @modules java.base/sun.security.validator
+ * @run main/othervm Distrust after policyOn invalid
+ * @run main/othervm Distrust after policyOff valid
+ * @run main/othervm Distrust before policyOn valid
+ * @run main/othervm Distrust before policyOff valid
+ */
+
+public class Distrust {
+
+    private static final String TEST_SRC = System.getProperty("test.src", ".");
+    private static CertificateFactory cf;
+
+    // Each of the roots have a test certificate chain stored in a file
+    // named "<root>-chain.pem".
+    private static String[] rootsToTest = new String[] {
+        "geotrustglobalca", "geotrustprimarycag2", "geotrustprimarycag3",
+        "geotrustuniversalca", "thawteprimaryrootca", "thawteprimaryrootcag2",
+        "thawteprimaryrootcag3", "verisignclass3g3ca", "verisignclass3g4ca",
+        "verisignclass3g5ca", "verisignuniversalrootca" };
+
+    // Each of the subCAs with a delayed distrust date have a test certificate
+    // chain stored in a file named "<subCA>-chain.pem".
+    private static String[] subCAsToTest = new String[] {
+        "appleistca2g1", "appleistca8g1" };
+
+    // A date that is after the restrictions take affect
+    private static final Date APRIL_17_2019 =
+        Date.from(LocalDate.of(2019, 4, 17)
+                           .atStartOfDay(ZoneOffset.UTC)
+                           .toInstant());
+
+    // A date that is a second before the restrictions take affect
+    private static final Date BEFORE_APRIL_17_2019 =
+        Date.from(LocalDate.of(2019, 4, 17)
+                           .atStartOfDay(ZoneOffset.UTC)
+                           .minusSeconds(1)
+                           .toInstant());
+
+    // A date that is after the subCA restrictions take affect
+    private static final Date JANUARY_1_2020 =
+        Date.from(LocalDate.of(2020, 1, 1)
+                           .atStartOfDay(ZoneOffset.UTC)
+                           .toInstant());
+
+    // A date that is a second before the subCA restrictions take affect
+    private static final Date BEFORE_JANUARY_1_2020 =
+        Date.from(LocalDate.of(2020, 1, 1)
+                           .atStartOfDay(ZoneOffset.UTC)
+                           .minusSeconds(1)
+                           .toInstant());
+
+    public static void main(String[] args) throws Exception {
+
+        cf = CertificateFactory.getInstance("X.509");
+
+        boolean before = args[0].equals("before");
+        boolean policyOn = args[1].equals("policyOn");
+        boolean isValid = args[2].equals("valid");
+
+        if (!policyOn) {
+            // disable policy (default is on)
+            Security.setProperty("jdk.security.caDistrustPolicies", "");
+        }
+
+        Date notBefore = before ? BEFORE_APRIL_17_2019 : APRIL_17_2019;
+
+        X509TrustManager pkixTM = getTMF("PKIX", null);
+        X509TrustManager sunX509TM = getTMF("SunX509", null);
+        for (String test : rootsToTest) {
+            System.err.println("Testing " + test);
+            X509Certificate[] chain = loadCertificateChain(test);
+
+            testTM(sunX509TM, chain, notBefore, isValid);
+            testTM(pkixTM, chain, notBefore, isValid);
+        }
+
+        // test chain if params are passed to TrustManager
+        System.err.println("Testing verisignuniversalrootca with params");
+        testTM(getTMF("PKIX", getParams()),
+               loadCertificateChain("verisignuniversalrootca"),
+               notBefore, isValid);
+
+        // test code-signing chain (should be valid as restrictions don't apply)
+        System.err.println("Testing verisignclass3g5ca code-signing chain");
+        Validator v = Validator.getInstance(Validator.TYPE_PKIX,
+                                            Validator.VAR_CODE_SIGNING,
+                                            getParams());
+        // set validation date so this will still pass when cert expires
+        v.setValidationDate(new Date(1544197375493l));
+        v.validate(loadCertificateChain("verisignclass3g5ca-codesigning"));
+
+        // test chains issued through subCAs
+        notBefore = before ? BEFORE_JANUARY_1_2020 : JANUARY_1_2020;
+        for (String test : subCAsToTest) {
+            System.err.println("Testing " + test);
+            X509Certificate[] chain = loadCertificateChain(test);
+
+            testTM(sunX509TM, chain, notBefore, isValid);
+            testTM(pkixTM, chain, notBefore, isValid);
+        }
+    }
+
+    private static X509TrustManager getTMF(String type,
+            PKIXBuilderParameters params) throws Exception {
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance(type);
+        if (params == null) {
+            tmf.init((KeyStore)null);
+        } else {
+            tmf.init(new CertPathTrustManagerParameters(params));
+        }
+        TrustManager[] tms = tmf.getTrustManagers();
+        for (TrustManager tm : tms) {
+            X509TrustManager xtm = (X509TrustManager)tm;
+            return xtm;
+        }
+        throw new Exception("No TrustManager for " + type);
+    }
+
+    private static PKIXBuilderParameters getParams() throws Exception {
+        PKIXBuilderParameters pbp =
+            new PKIXBuilderParameters(SecurityUtils.getCacertsKeyStore(),
+                                      new X509CertSelector());
+        pbp.setRevocationEnabled(false);
+        return pbp;
+    }
+
+    private static void testTM(X509TrustManager xtm, X509Certificate[] chain,
+                               Date notBefore, boolean valid) throws Exception {
+        // Check if TLS Server certificate (the first element of the chain)
+        // is issued after the specified notBefore date (should be rejected
+        // unless distrust property is false). To do this, we need to
+        // fake the notBefore date since none of the test certs are issued
+        // after then.
+        chain[0] = new DistrustedTLSServerCert(chain[0], notBefore);
+
+        try {
+            xtm.checkServerTrusted(chain, "ECDHE_RSA");
+            if (!valid) {
+                throw new Exception("chain should be invalid");
+            }
+        } catch (CertificateException ce) {
+            if (valid) {
+                throw new Exception("Unexpected exception, chain " +
+                                    "should be valid", ce);
+            }
+            if (ce instanceof ValidatorException) {
+                ValidatorException ve = (ValidatorException)ce;
+                if (ve.getErrorType() != ValidatorException.T_UNTRUSTED_CERT) {
+                    throw new Exception("Unexpected exception: " + ce);
+                }
+            } else {
+                throw new Exception("Unexpected exception: " + ce);
+            }
+        }
+    }
+
+    private static X509Certificate[] loadCertificateChain(String name)
+            throws Exception {
+        try (InputStream in = new FileInputStream(TEST_SRC + File.separator +
+                                                  name + "-chain.pem")) {
+            Collection<X509Certificate> certs =
+                (Collection<X509Certificate>)cf.generateCertificates(in);
+            return certs.toArray(new X509Certificate[0]);
+        }
+    }
+
+    private static class DistrustedTLSServerCert extends X509Certificate {
+        private final X509Certificate cert;
+        private final Date notBefore;
+        DistrustedTLSServerCert(X509Certificate cert, Date notBefore) {
+            this.cert = cert;
+            this.notBefore = notBefore;
+        }
+        public Set<String> getCriticalExtensionOIDs() {
+           return cert.getCriticalExtensionOIDs();
+        }
+        public byte[] getExtensionValue(String oid) {
+            return cert.getExtensionValue(oid);
+        }
+        public Set<String> getNonCriticalExtensionOIDs() {
+            return cert.getNonCriticalExtensionOIDs();
+        }
+        public boolean hasUnsupportedCriticalExtension() {
+            return cert.hasUnsupportedCriticalExtension();
+        }
+        public void checkValidity() throws CertificateExpiredException,
+            CertificateNotYetValidException {
+            // always pass
+        }
+        public void checkValidity(Date date) throws CertificateExpiredException,
+            CertificateNotYetValidException {
+            // always pass
+        }
+        public int getVersion() { return cert.getVersion(); }
+        public BigInteger getSerialNumber() { return cert.getSerialNumber(); }
+        public Principal getIssuerDN() { return cert.getIssuerDN(); }
+        public Principal getSubjectDN() { return cert.getSubjectDN(); }
+        public Date getNotBefore() { return notBefore; }
+        public Date getNotAfter() { return cert.getNotAfter(); }
+        public byte[] getTBSCertificate() throws CertificateEncodingException {
+            return cert.getTBSCertificate();
+        }
+        public byte[] getSignature() { return cert.getSignature(); }
+        public String getSigAlgName() { return cert.getSigAlgName(); }
+        public String getSigAlgOID() { return cert.getSigAlgOID(); }
+        public byte[] getSigAlgParams() { return cert.getSigAlgParams(); }
+        public boolean[] getIssuerUniqueID() {
+            return cert.getIssuerUniqueID();
+        }
+        public boolean[] getSubjectUniqueID() {
+            return cert.getSubjectUniqueID();
+        }
+        public boolean[] getKeyUsage() { return cert.getKeyUsage(); }
+        public int getBasicConstraints() { return cert.getBasicConstraints(); }
+        public byte[] getEncoded() throws CertificateEncodingException {
+            return cert.getEncoded();
+        }
+        public void verify(PublicKey key) throws CertificateException,
+            InvalidKeyException, NoSuchAlgorithmException,
+            NoSuchProviderException, SignatureException {
+            cert.verify(key);
+        }
+        public void verify(PublicKey key, String sigProvider) throws
+            CertificateException, InvalidKeyException, NoSuchAlgorithmException,
+            NoSuchProviderException, SignatureException {
+            cert.verify(key, sigProvider);
+        }
+        public PublicKey getPublicKey() { return cert.getPublicKey(); }
+        public String toString() { return cert.toString(); }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/internal/TestRun.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8145255
+ * @run main/othervm java.base/sun.security.ssl.TestHkdf
+ * @summary HKDF for Sun JSSE
+ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/internal/java.base/sun/security/ssl/TestHkdf.java	Tue Aug 25 18:12:01 2020 +0300
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * 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.
+ */
+
+/*
+ * Actual test code for the package private HKDF implementation
+ */
+
+package sun.security.ssl;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Objects;
+import java.security.NoSuchAlgorithmException;
+import java.security.InvalidKeyException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+public class TestHkdf {
+    public static class TestData {
+        public TestData(String name, String algStr, String ikmStr,
+                String saltStr, String infoStr, int oLen, String expPrkStr,
+                String expOkmStr) {
+            testName = Objects.requireNonNull(name);
+            algName = Objects.requireNonNull(algStr);
+            IKM = hex2bin(Objects.requireNonNull(ikmStr));
+            if ((outLen = oLen) <= 0) {
+                throw new IllegalArgumentException(
+                        "Output length must be greater than 0");
+            }
+            expectedPRK = hex2bin(Objects.requireNonNull(expPrkStr));
+            expectedOKM = hex2bin(Objects.requireNonNull(expOkmStr));
+
+            // Non-mandatory fields - may be null
+            salt = (saltStr != null) ? hex2bin(saltStr) : null;
+            info = (infoStr != null) ? hex2bin(infoStr) : null;
+        }
+
+        public final String testName;
+        public final String algName;
+        public final byte[] IKM;
+        public final byte[] salt;
+        public final byte[] info;
+        public final int outLen;
+        public final byte[] expectedPRK;
+        public final byte[] expectedOKM;
+    }
+
+    public static final List<TestData> testList = new LinkedList<TestData>() {{
+        add(new TestData("RFC 5689 Test Case 1", "SHA-256",
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            "000102030405060708090a0b0c",
+            "f0f1f2f3f4f5f6f7f8f9",
+            42,
+            "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5",
+            "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf" +
+            "34007208d5b887185865"));
+        add(new TestData("RFC 5689 Test Case 2", "SHA-256",
+            "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+            "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+            "404142434445464748494a4b4c4d4e4f",
+            "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
+            "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" +
+            "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+            "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
+            "d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
+            "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+            82,
+            "06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244",
+            "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c" +
+            "59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71" +
+            "cc30c58179ec3e87c14c01d5c1f3434f1d87"));
+        add(new TestData("RFC 5689 Test Case 3", "SHA-256",
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            null, null, 42,
+            "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04",
+            "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d" +
+            "9d201395faa4b61a96c8"));
+        add(new TestData("RFC 5689 Test Case 4", "SHA-1",
+            "0b0b0b0b0b0b0b0b0b0b0b",
+            "000102030405060708090a0b0c",
+            "f0f1f2f3f4f5f6f7f8f9",
+            42,
+            "9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243",
+            "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2" +
+            "c22e422478d305f3f896"));
+        add(new TestData("RFC 5689 Test Case 5", "SHA-1",
+            "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" +
+            "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" +
+            "404142434445464748494a4b4c4d4e4f",
+            "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f" +
+            "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f" +
+            "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+            "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf" +
+            "d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef" +
+            "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+            82,
+            "8adae09a2a307059478d309b26c4115a224cfaf6",
+            "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe" +
+            "8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e" +
+            "927336d0441f4c4300e2cff0d0900b52d3b4"));
+        add(new TestData("RFC 5689 Test Case 6", "SHA-1",
+            "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+            null, null, 42,
+            "da8c8a73c7fa77288ec6f5e7c297786aa0d32d01",
+            "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0" +
+            "ea00033de03984d34918"));
+        add(new TestData("RFC 5689 Test Case 7", "SHA-1",
+            "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+            null, null, 42,
+            "2adccada18779e7c2077ad2eb19d3f3e731385dd",
+            "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5" +
+            "673a081d70cce7acfc48"));
+    }};
+
+    public static void main(String args[]) throws Exception {
+        int testsPassed = 0;
+
+        int testNo = 0;
+        for (TestData test : testList) {
+            System.out.println("*** Test " + ++testNo + ": " +
+                    test.testName);
+            if (runVector(test)) {
+                testsPassed++;
+            }
+        }
+
+        System.out.println("Total tests: " + testList.size() +
+                ", Passed: " + testsPassed + ", Failed: " +
+                (testList.size() - testsPassed));
+        if (testsPassed != testList.size()) {
+            throw new RuntimeException("One or more tests failed.  " +
+                    "Check output for details");
+        }
+    }
+
+    private static boolean runVector(TestData testData)
+            throws NoSuchAlgorithmException, InvalidKeyException {
+        String kdfName, prfName;
+        HKDF kdfHkdf;
+        boolean result = true;
+        SecretKey actualPRK;
+        SecretKey actualOKM;
+        byte[] deriveData;
+
+        // Get an instance of the HKDF derivation engine
+        kdfHkdf = new HKDF(testData.algName);
+
+        // Set up the input keying material and the salt as a secret
+        SecretKey ikmKey = new SecretKeySpec(testData.IKM, "HKDF-IKM");
+        SecretKey saltKey = (testData.salt != null) ?
+                new SecretKeySpec(testData.salt, "HKDF-Salt") : null;
+
+        // *** HKDF-Extract-only testing
+        System.out.println("* HKDF-Extract-Only:");
+        actualPRK = kdfHkdf.extract(saltKey, ikmKey, "HKDF-PRK");
+        result &= compareKeyAndData(actualPRK, testData.expectedPRK);
+
+        // *** HKDF Expand-Only testing
+        // For these tests, we'll use the actualPRK as the input key
+        System.out.println("* HKDF-Expand-Only:");
+        actualOKM = kdfHkdf.expand(actualPRK, testData.info, testData.outLen,
+                "HKDF-OKM");
+        result &= compareKeyAndData(actualOKM, testData.expectedOKM);
+
+        // *** HKDF Extract-then-Expand testing
+        // System.out.println("* HKDF-Extract-then-Expand:");
+        // actualOKM = kdfHkdf.extractExpand(ikmKey, saltKey, testData.info,
+        //         testData.outLen, "HKDF-OKM2");
+        // result &= compareKeyAndData(actualOKM, testData.expectedOKM);
+
+        return result;
+    }
+
+    /**
+     * Compare actual key output from HKDF against an expected output value.
+     *
+     * @param outKey the KDF output in key form
+     * @param expectedOut the expected value
+     *
+     * @return true if the underlying data for outKey, outData and
+     * expectedOut are the same.
+     */
+    private static boolean compareKeyAndData(SecretKey outKey,
+            byte[] expectedOut) {
+        boolean result = false;
+
+        if (Arrays.equals(outKey.getEncoded(), expectedOut)) {
+            System.out.println("\t* Key output: Pass");
+            result = true;
+        } else {
+            System.out.println("\t* Key output: FAIL");
+            System.out.println("Expected:\n" +
+                    dumpHexBytes(expectedOut, 16, "\n", " "));
+            System.out.println("Actual:\n" +
+                    dumpHexBytes(outKey.getEncoded(), 16, "\n", " "));
+            System.out.println();
+        }
+
+        return result;
+    }
+
+    /**
+     * Dump the hex bytes of a buffer into string form.
+     *
+     * @param data The array of bytes to dump to stdout.
+     * @param itemsPerLine The number of bytes to display per line
+     *      if the {@code lineDelim} character is blank then all bytes
+     *      will be printed on a single line.
+     * @param lineDelim The delimiter between lines
+     * @param itemDelim The delimiter between bytes
+     *
+     * @return The hexdump of the byte array
+     */
+    private static String dumpHexBytes(byte[] data, int itemsPerLine,
+            String lineDelim, String itemDelim) {
+        StringBuilder sb = new StringBuilder();
+        if (data != null) {
+            for (int i = 0; i < data.length; i++) {
+                if (i % itemsPerLine == 0 && i != 0) {
+                    sb.append(lineDelim);
+                }
+                sb.append(String.format("%02X", data[i])).append(itemDelim);
+            }
+        }
+
+        return sb.toString();
+    }
+
+    private static byte[] hex2bin(String hex) {
+        int i;
+        int len = hex.length();
+        byte[] data = new byte [len / 2];
+        for (i = 0; i < len; i += 2) {
+            data[i / 2] = (byte)((Character.digit(hex.charAt(i), 16) << 4) +
+                    Character.digit(hex.charAt(i + 1), 16));
+        }
+        return data;
+    }
+}