8148188: Enhance the security libraries to record events of interest
authorcoffeys
Tue, 20 Nov 2018 13:12:48 +0000
changeset 52621 f7309a1491d9
parent 52620 5f47b56cb867
child 52622 7a8af2f1f0c5
8148188: Enhance the security libraries to record events of interest Reviewed-by: egahlin, mullan, weijun, xuelei
src/java.base/share/classes/java/security/Security.java
src/java.base/share/classes/jdk/internal/event/EventHelper.java
src/java.base/share/classes/jdk/internal/event/SecurityPropertyModificationEvent.java
src/java.base/share/classes/jdk/internal/event/TLSHandshakeEvent.java
src/java.base/share/classes/jdk/internal/event/X509CertificateEvent.java
src/java.base/share/classes/jdk/internal/event/X509ValidationEvent.java
src/java.base/share/classes/sun/security/provider/X509Factory.java
src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java
src/java.base/share/classes/sun/security/ssl/Finished.java
src/jdk.jfr/share/classes/jdk/jfr/events/CertificateId.java
src/jdk.jfr/share/classes/jdk/jfr/events/SecurityPropertyModificationEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/TLSHandshakeEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/X509CertificateEvent.java
src/jdk.jfr/share/classes/jdk/jfr/events/X509ValidationEvent.java
src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java
src/jdk.jfr/share/conf/jfr/default.jfc
src/jdk.jfr/share/conf/jfr/profile.jfc
test/jdk/jdk/jfr/event/metadata/TestDefaultConfigurations.java
test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java
test/jdk/jdk/jfr/event/runtime/TestModuleEvents.java
test/jdk/jdk/jfr/event/security/TestSecurityPropertyModificationEvent.java
test/jdk/jdk/jfr/event/security/TestTLSHandshakeEvent.java
test/jdk/jdk/jfr/event/security/TestX509CertificateEvent.java
test/jdk/jdk/jfr/event/security/TestX509ValidationEvent.java
test/jdk/jdk/security/logging/LogJvm.java
test/jdk/jdk/security/logging/TestSecurityPropertyModificationLog.java
test/jdk/jdk/security/logging/TestTLSHandshakeLog.java
test/jdk/jdk/security/logging/TestX509CertificateLog.java
test/jdk/jdk/security/logging/TestX509ValidationLog.java
test/jdk/jdk/security/logging/logging.properties
test/lib/jdk/test/lib/jfr/EventNames.java
test/lib/jdk/test/lib/security/JDKSecurityProperties.java
test/lib/jdk/test/lib/security/SSLSocketTest.java
test/lib/jdk/test/lib/security/TestCertificate.java
test/lib/jdk/test/lib/security/TestTLSHandshake.java
--- a/src/java.base/share/classes/java/security/Security.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/java.base/share/classes/java/security/Security.java	Tue Nov 20 13:12:48 2018 +0000
@@ -30,6 +30,8 @@
 import java.io.*;
 import java.net.URL;
 
+import jdk.internal.event.EventHelper;
+import jdk.internal.event.SecurityPropertyModificationEvent;
 import jdk.internal.access.SharedSecrets;
 import jdk.internal.util.StaticProperty;
 import sun.security.util.Debug;
@@ -792,9 +794,19 @@
      * @see java.security.SecurityPermission
      */
     public static void setProperty(String key, String datum) {
-        check("setProperty."+key);
+        check("setProperty." + key);
         props.put(key, datum);
         invalidateSMCache(key);  /* See below. */
+
+        SecurityPropertyModificationEvent spe = new SecurityPropertyModificationEvent();
+        // following is a no-op if event is disabled
+        spe.key = key;
+        spe.value = datum;
+        spe.commit();
+
+        if (EventHelper.isLoggingSecurity()) {
+            EventHelper.logSecurityPropertyEvent(key, datum);
+        }
     }
 
     /*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/event/EventHelper.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+package jdk.internal.event;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * A helper class to have events logged to a JDK Event Logger.
+ */
+
+public final class EventHelper {
+
+    private static final System.Logger.Level LOG_LEVEL = System.Logger.Level.DEBUG;
+
+    // helper class used for logging security related events for now
+    private static final String SECURITY_LOGGER_NAME = "jdk.event.security";
+    private static final System.Logger SECURITY_LOGGER =
+            System.getLogger(SECURITY_LOGGER_NAME);
+    private static final boolean LOGGING_SECURITY =
+            SECURITY_LOGGER.isLoggable(LOG_LEVEL);
+
+    public static void logTLSHandshakeEvent(Instant start,
+                                            String peerHost,
+                                            int peerPort,
+                                            String cipherSuite,
+                                            String protocolVersion,
+                                            long peerCertId) {
+        String prepend = getDurationString(start);
+        SECURITY_LOGGER.log(LOG_LEVEL, prepend +
+        " TLSHandshake: {0}:{1,number,#}, {2}, {3}, {4,number,#}",
+        peerHost, peerPort, protocolVersion, cipherSuite, peerCertId);
+    }
+
+    public static void logSecurityPropertyEvent(String key,
+                                                String value) {
+
+        if (isLoggingSecurity()) {
+            SECURITY_LOGGER.log(LOG_LEVEL,
+                "SecurityPropertyModification: key:{0}, value:{1}", key, value);
+        }
+    }
+
+    public static void logX509ValidationEvent(int anchorCertId,
+                                         int[] certIds) {
+        String codes = IntStream.of(certIds)
+                .mapToObj(Integer::toString)
+                .collect(Collectors.joining(", "));
+        SECURITY_LOGGER.log(LOG_LEVEL,
+                "ValidationChain: {0,number,#}, {1}", anchorCertId, codes);
+    }
+
+    public static void logX509CertificateEvent(String algId,
+                                               String serialNum,
+                                               String subject,
+                                               String issuer,
+                                               String keyType,
+                                               int length,
+                                               long certId,
+                                               long beginDate,
+                                               long endDate) {
+        SECURITY_LOGGER.log(LOG_LEVEL, "X509Certificate: Alg:{0}, Serial:{1}" +
+            ", Subject:{2}, Issuer:{3}, Key type:{4}, Length:{5,number,#}" +
+            ", Cert Id:{6,number,#}, Valid from:{7}, Valid until:{8}",
+            algId, serialNum, subject, issuer, keyType, length,
+            certId, new Date(beginDate), new Date(endDate));
+    }
+
+    /**
+     * Method to calculate a duration timestamp for events which measure
+     * the start and end times of certain operations.
+     * @param start Instant indicating when event started recording
+     * @return A string representing duraction from start time to
+     * time of this method call. Empty string is start is null.
+     */
+    private static String getDurationString(Instant start) {
+        if (start != null) {
+            Duration duration = Duration.between(start, Instant.now());
+            long micros = duration.toNanos() / 1_000;
+            if (micros < 1_000_000) {
+                return "duration = " + (micros / 1_000.0) + " ms:";
+            } else {
+                return "duration = " + ((micros / 1_000) / 1_000.0) + " s:";
+            }
+        } else {
+            return "";
+        }
+    }
+
+    /**
+     * Helper to determine if security events are being logged
+     * at a preconfigured logging level. The configuration value
+     * is read once at class initialization.
+     *
+     * @return boolean indicating whether an event should be logged
+     */
+    public static boolean isLoggingSecurity() {
+        return LOGGING_SECURITY;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/event/SecurityPropertyModificationEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package jdk.internal.event;
+
+/**
+ * Event details relating to the modification of a Security property.
+ */
+
+public final class SecurityPropertyModificationEvent extends Event {
+    public String key;
+    public String value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/event/TLSHandshakeEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package jdk.internal.event;
+
+/**
+ * Event recording details of successful TLS handshakes.
+ */
+
+public final class TLSHandshakeEvent extends Event {
+    public String peerHost;
+    public int peerPort;
+    public String protocolVersion;
+    public String cipherSuite;
+    public long certificateId;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/event/X509CertificateEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package jdk.internal.event;
+
+
+/**
+ * Event recording details of X.509 Certificate.
+ */
+
+public final class X509CertificateEvent extends Event {
+    public String algorithm;
+    public String serialNumber;
+    public String subject;
+    public String issuer;
+    public String keyType;
+    public int keyLength;
+    public long certificateId;
+    public long validFrom;
+    public long validUntil;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/event/X509ValidationEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+package jdk.internal.event;
+
+/**
+ * Event recording details of X.509 Certificate serial numbers
+ * used in X509 cert path validation.
+ */
+
+public final class X509ValidationEvent extends Event {
+    public long certificateId;
+    public int certificatePosition;
+    public long validationCounter;
+}
--- a/src/java.base/share/classes/sun/security/provider/X509Factory.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java	Tue Nov 20 13:12:48 2018 +0000
@@ -26,12 +26,15 @@
 package sun.security.provider;
 
 import java.io.*;
+import java.security.PublicKey;
 import java.util.*;
 import java.security.cert.*;
 
+import jdk.internal.event.EventHelper;
+import jdk.internal.event.X509CertificateEvent;
+import sun.security.util.KeyUtil;
 import sun.security.util.Pem;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.X509CRLImpl;
+import sun.security.x509.*;
 import sun.security.pkcs.PKCS7;
 import sun.security.provider.certpath.X509CertPath;
 import sun.security.provider.certpath.X509CertificatePair;
@@ -101,6 +104,8 @@
                 }
                 cert = new X509CertImpl(encoding);
                 addToCache(certCache, cert.getEncodedInternal(), cert);
+                // record cert details if necessary
+                commitEvent(cert);
                 return cert;
             } else {
                 throw new IOException("Empty input");
@@ -762,4 +767,43 @@
         }
         return tag;
     }
+
+    private void commitEvent(X509CertImpl info) {
+        X509CertificateEvent xce = new X509CertificateEvent();
+        if (xce.shouldCommit() || EventHelper.isLoggingSecurity()) {
+            PublicKey pKey = info.getPublicKey();
+            String algId = info.getSigAlgName();
+            String serNum = info.getSerialNumber().toString(16);
+            String subject = info.getSubjectDN().getName();
+            String issuer = info.getIssuerDN().getName();
+            String keyType = pKey.getAlgorithm();
+            int length = KeyUtil.getKeySize(pKey);
+            int hashCode = info.hashCode();
+            long beginDate = info.getNotBefore().getTime();
+            long endDate = info.getNotAfter().getTime();
+            if (xce.shouldCommit()) {
+                xce.algorithm = algId;
+                xce.serialNumber = serNum;
+                xce.subject = subject;
+                xce.issuer = issuer;
+                xce.keyType = keyType;
+                xce.keyLength = length;
+                xce.certificateId = hashCode;
+                xce.validFrom = beginDate;
+                xce.validUntil = endDate;
+                xce.commit();
+            }
+            if (EventHelper.isLoggingSecurity()) {
+                EventHelper.logX509CertificateEvent(algId,
+                        serNum,
+                        subject,
+                        issuer,
+                        keyType,
+                        length,
+                        hashCode,
+                        beginDate,
+                        endDate);
+            }
+        }
+    }
 }
--- a/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/java.base/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Nov 20 13:12:48 2018 +0000
@@ -29,7 +29,10 @@
 import java.security.InvalidAlgorithmParameterException;
 import java.security.cert.*;
 import java.util.*;
+import java.util.concurrent.atomic.AtomicLong;
 
+import jdk.internal.event.X509ValidationEvent;
+import jdk.internal.event.EventHelper;
 import sun.security.provider.certpath.PKIX.ValidatorParams;
 import sun.security.validator.Validator;
 import sun.security.x509.X509CertImpl;
@@ -47,6 +50,7 @@
 public final class PKIXCertPathValidator extends CertPathValidatorSpi {
 
     private static final Debug debug = Debug.getInstance("certpath");
+    private static final AtomicLong validationCounter = new AtomicLong();
 
     /**
      * Default constructor.
@@ -234,7 +238,33 @@
                                              params.certificates(),
                                              certPathCheckers);
 
+        X509ValidationEvent xve = new X509ValidationEvent();
+        if (xve.shouldCommit() || EventHelper.isLoggingSecurity()) {
+            int[] certIds = params.certificates().stream()
+                    .mapToInt(x -> x.hashCode())
+                    .toArray();
+            int anchorCertId =
+                    anchor.getTrustedCert().hashCode();
+            if (xve.shouldCommit()) {
+                xve.certificateId = anchorCertId;
+                int certificatePos = 1; //anchor cert
+                xve.certificatePosition = certificatePos;
+                xve.validationCounter = validationCounter.incrementAndGet();
+                xve.commit();
+                // now, iterate through remaining
+                for (int id : certIds) {
+                    xve.certificateId = id;
+                    xve.certificatePosition = ++certificatePos;
+                    xve.commit();
+
+                }
+            }
+            if (EventHelper.isLoggingSecurity()) {
+                EventHelper.logX509ValidationEvent(anchorCertId, certIds);
+            }
+        }
         return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
                                                bc.getPublicKey());
     }
+
 }
--- a/src/java.base/share/classes/sun/security/ssl/Finished.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/Finished.java	Tue Nov 20 13:12:48 2018 +0000
@@ -40,6 +40,10 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLPeerUnverifiedException;
+
+import jdk.internal.event.EventHelper;
+import jdk.internal.event.TLSHandshakeEvent;
 import sun.security.internal.spec.TlsPrfParameterSpec;
 import sun.security.ssl.CipherSuite.HashAlg;
 import static sun.security.ssl.CipherSuite.HashAlg.H_NONE;
@@ -548,6 +552,7 @@
 
                 // handshake context cleanup.
                 chc.handshakeFinished = true;
+                recordEvent(chc.conContext.conSession);
 
                 // May need to retransmit the last flight for DTLS.
                 if (!chc.sslContext.isDTLS()) {
@@ -597,6 +602,7 @@
 
                 // handshake context cleanup.
                 shc.handshakeFinished = true;
+                recordEvent(shc.conContext.conSession);
 
                 // May need to retransmit the last flight for DTLS.
                 if (!shc.sslContext.isDTLS()) {
@@ -730,6 +736,8 @@
             // handshake context cleanup.
             chc.handshakeFinished = true;
             chc.conContext.finishHandshake();
+            recordEvent(chc.conContext.conSession);
+
 
             // The handshake message has been delivered.
             return null;
@@ -1063,6 +1071,7 @@
             if (!shc.sslContext.isDTLS()) {
                 shc.conContext.finishHandshake();
             }
+            recordEvent(shc.conContext.conSession);
 
             //
             // produce
@@ -1074,4 +1083,35 @@
 
         }
     }
+
+    private static void recordEvent(SSLSessionImpl session) {
+        TLSHandshakeEvent event = new TLSHandshakeEvent();
+        if (event.shouldCommit() || EventHelper.isLoggingSecurity()) {
+            int peerCertificateId = 0;
+            try {
+                // use hash code for Id
+                peerCertificateId = session
+                        .getCertificateChain()[0]
+                        .hashCode();
+            } catch (SSLPeerUnverifiedException e) {
+                 // not verified msg
+            }
+            if (event.shouldCommit()) {
+                event.peerHost = session.getPeerHost();
+                event.peerPort = session.getPeerPort();
+                event.cipherSuite = session.getCipherSuite();
+                event.protocolVersion = session.getProtocol();
+                event.certificateId = peerCertificateId;
+                event.commit();
+            }
+            if (EventHelper.isLoggingSecurity()) {
+                EventHelper.logTLSHandshakeEvent(null,
+                                session.getPeerHost(),
+                                session.getPeerPort(),
+                                session.getCipherSuite(),
+                                session.getProtocol(),
+                                peerCertificateId);
+            }
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/CertificateId.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Label;
+import jdk.jfr.Relational;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Label("X509 Certificate Id")
+@Relational
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface CertificateId {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/SecurityPropertyModificationEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.*;
+import jdk.jfr.internal.MirrorEvent;
+
+@Category({"Java Development Kit", "Security"})
+@Label("Security Property Modification")
+@Name("jdk.SecurityPropertyModification")
+@Description("Modification of Security property")
+@MirrorEvent(className = "jdk.internal.event.SecurityPropertyModificationEvent")
+public final class SecurityPropertyModificationEvent extends AbstractJDKEvent {
+    @Label("Key")
+    public String key;
+
+    @Label("Value")
+    public String value;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/TLSHandshakeEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.Category;
+import jdk.jfr.Description;
+import jdk.jfr.Label;
+import jdk.jfr.Name;
+import jdk.jfr.internal.MirrorEvent;
+
+@Category({"Java Development Kit", "Security"})
+@Label("TLS Handshake")
+@Name("jdk.TLSHandshake")
+@Description("Parameters used in TLS Handshake")
+@MirrorEvent(className = "jdk.internal.event.TLSHandshakeEvent")
+public final class TLSHandshakeEvent extends AbstractJDKEvent {
+    @Label("Peer Host")
+    public String peerHost;
+
+    @Label("Peer Port")
+    public int peerPort;
+
+    @Label("Protocol Version")
+    public String protocolVersion;
+
+    @Label("Cipher Suite")
+    public String cipherSuite;
+
+    @Label("Certificate Id")
+    @Description("Peer Certificate Id")
+    @CertificateId
+    public long certificateId;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/X509CertificateEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.*;
+import jdk.jfr.internal.MirrorEvent;
+
+@Category({"Java Development Kit", "Security"})
+@Label("X509 Certificate")
+@Name("jdk.X509Certificate")
+@Description("Details of X.509 Certificate parsed by JDK")
+@MirrorEvent(className = "jdk.internal.event.X509CertificateEvent")
+public final class X509CertificateEvent extends AbstractJDKEvent {
+    @Label("Signature Algorithm")
+    public String algorithm;
+
+    @Label("Serial Number")
+    public String serialNumber;
+
+    @Label("Subject")
+    public String subject;
+
+    @Label("Issuer")
+    public String issuer;
+
+    @Label("Key Type")
+    public String keyType;
+
+    @Label("Key Length")
+    public int keyLength;
+
+    @Label("Certificate Id")
+    @CertificateId
+    public long certificateId;
+
+    @Label("Valid From")
+    @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
+    public long validFrom;
+
+    @Label("Valid Until")
+    @Timestamp(Timestamp.MILLISECONDS_SINCE_EPOCH)
+    public long validUntil;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jfr/share/classes/jdk/jfr/events/X509ValidationEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.events;
+
+import jdk.jfr.*;
+import jdk.jfr.internal.MirrorEvent;
+
+@Category({"Java Development Kit", "Security"})
+@Label("X509 Validation")
+@Name("jdk.X509Validation")
+@Description("Serial numbers from X.509 Certificates forming chain of trust")
+@MirrorEvent(className = "jdk.internal.event.X509ValidationEvent")
+public final class X509ValidationEvent extends AbstractJDKEvent {
+    @CertificateId
+    @Label("Certificate Id")
+    public long certificateId;
+
+    @Label("Certificate Position")
+    @Description("Certificate position in chain of trust, 1 = trust anchor")
+    public int certificatePosition;
+
+    @Label("Validation Counter")
+    public long validationCounter;
+}
--- a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/JDKEvents.java	Tue Nov 20 13:12:48 2018 +0000
@@ -39,8 +39,12 @@
 import jdk.jfr.events.FileForceEvent;
 import jdk.jfr.events.FileReadEvent;
 import jdk.jfr.events.FileWriteEvent;
+import jdk.jfr.events.SecurityPropertyModificationEvent;
 import jdk.jfr.events.SocketReadEvent;
 import jdk.jfr.events.SocketWriteEvent;
+import jdk.jfr.events.TLSHandshakeEvent;
+import jdk.jfr.events.X509CertificateEvent;
+import jdk.jfr.events.X509ValidationEvent;
 import jdk.jfr.internal.JVM;
 import jdk.jfr.internal.LogLevel;
 import jdk.jfr.internal.LogTag;
@@ -52,6 +56,10 @@
 public final class JDKEvents {
 
     private static final Class<?>[] mirrorEventClasses = {
+        SecurityPropertyModificationEvent.class,
+        TLSHandshakeEvent.class,
+        X509CertificateEvent.class,
+        X509ValidationEvent.class
     };
 
     private static final Class<?>[] eventClasses = {
@@ -64,7 +72,11 @@
         ExceptionStatisticsEvent.class,
         ErrorThrownEvent.class,
         ActiveSettingEvent.class,
-        ActiveRecordingEvent.class
+        ActiveRecordingEvent.class,
+        jdk.internal.event.SecurityPropertyModificationEvent.class,
+        jdk.internal.event.TLSHandshakeEvent.class,
+        jdk.internal.event.X509CertificateEvent.class,
+        jdk.internal.event.X509ValidationEvent.class
     };
 
     // This is a list of the classes with instrumentation code that should be applied.
--- a/src/jdk.jfr/share/conf/jfr/default.jfc	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/jdk.jfr/share/conf/jfr/default.jfc	Tue Nov 20 13:12:48 2018 +0000
@@ -593,6 +593,26 @@
       <setting name="threshold" control="socket-io-threshold">20 ms</setting>
     </event>
 
+    <event name="jdk.SecurityPropertyModification">
+       <setting name="enabled">false</setting>
+       <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.TLSHandshake">
+      <setting name="enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.X509Validation">
+       <setting name="enabled">false</setting>
+       <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.X509Certificate">
+       <setting name="enabled">false</setting>
+       <setting name="stackTrace">true</setting>
+    </event>
+
     <event name="jdk.JavaExceptionThrow">
       <setting name="enabled" control="enable-exceptions">false</setting>
       <setting name="stackTrace">true</setting>
--- a/src/jdk.jfr/share/conf/jfr/profile.jfc	Tue Nov 20 10:08:19 2018 +0100
+++ b/src/jdk.jfr/share/conf/jfr/profile.jfc	Tue Nov 20 13:12:48 2018 +0000
@@ -593,6 +593,26 @@
       <setting name="threshold" control="socket-io-threshold">10 ms</setting>
     </event>
 
+    <event name="jdk.SecurityPropertyModification">
+       <setting name="enabled">false</setting>
+       <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.TLSHandshake">
+      <setting name="enabled">false</setting>
+      <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.X509Validation">
+       <setting name="enabled">false</setting>
+       <setting name="stackTrace">true</setting>
+    </event>
+
+    <event name="jdk.X509Certificate">
+       <setting name="enabled">false</setting>
+       <setting name="stackTrace">true</setting>
+    </event>
+
     <event name="jdk.JavaExceptionThrow">
       <setting name="enabled" control="enable-exceptions">false</setting>
       <setting name="stackTrace">true</setting>
--- a/test/jdk/jdk/jfr/event/metadata/TestDefaultConfigurations.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/test/jdk/jdk/jfr/event/metadata/TestDefaultConfigurations.java	Tue Nov 20 13:12:48 2018 +0000
@@ -173,6 +173,10 @@
         insertSetting(doc, EventNames.ActiveRecording, "threshold", "0 ns");
         insertSetting(doc, EventNames.JavaExceptionThrow, "threshold", "0 ns");
         insertSetting(doc, EventNames.JavaErrorThrow, "threshold", "0 ns");
+        insertSetting(doc, EventNames.SecurityProperty, "threshold", "0 ns");
+        insertSetting(doc, EventNames.TLSHandshake, "threshold", "0 ns");
+        insertSetting(doc, EventNames.X509Certificate, "threshold", "0 ns");
+        insertSetting(doc, EventNames.X509Validation, "threshold", "0 ns");
         return doc;
     }
 
--- a/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/test/jdk/jdk/jfr/event/runtime/TestActiveSettingEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -201,6 +201,10 @@
         settingValues.put(EventNames.ActiveRecording + "#threshold", "0 ns");
         settingValues.put(EventNames.JavaExceptionThrow + "#threshold", "0 ns");
         settingValues.put(EventNames.JavaErrorThrow + "#threshold", "0 ns");
+        settingValues.put(EventNames.SecurityProperty + "#threshold", "0 ns");
+        settingValues.put(EventNames.TLSHandshake + "#threshold", "0 ns");
+        settingValues.put(EventNames.X509Certificate + "#threshold", "0 ns");
+        settingValues.put(EventNames.X509Validation + "#threshold", "0 ns");
 
         try (Recording recording = new Recording(c)) {
             Map<Long, EventType> eventTypes = new HashMap<>();
--- a/test/jdk/jdk/jfr/event/runtime/TestModuleEvents.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/test/jdk/jdk/jfr/event/runtime/TestModuleEvents.java	Tue Nov 20 13:12:48 2018 +0000
@@ -64,8 +64,8 @@
         recording.stop();
 
         List<RecordedEvent> events = Events.fromRecording(recording);
-        assertDependency(events, "jdk.jfr", "java.base"); // jdk.jfr requires java.base (by edfault)
-        assertDependency(events, "java.base", "jdk.jfr"); // java.base require jdk.jfr for JDK events, i.e. FileRead
+        assertDependency(events, "jdk.jfr", "java.base"); // jdk.jfr requires java.base (by default)
+        assertDependency(events, "java.base", "jdk.jfr"); // java.base requires jdk.jfr for JDK events, i.e. FileRead
 
         recording.close();
     }
@@ -97,8 +97,9 @@
         events.stream().forEach((ev) -> {
             String exportedPackage = getValue(ev.getValue("exportedPackage"), "name", UNNAMED);
             String toModule = getValue(ev.getValue("targetModule"), "name", UNNAMED);
-
-            edges.put(exportedPackage, toModule);
+            if (!toModule.equals("jdk.proxy1")) { // ignore jdk.proxy1 module
+                edges.put(exportedPackage, toModule);
+            }
         });
 
         // We expect
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/security/TestSecurityPropertyModificationEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.event.security;
+
+import java.security.Security;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.security.JDKSecurityProperties;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.security.TestSecurityPropertyModificationEvent
+ */
+public class TestSecurityPropertyModificationEvent {
+
+    static List<String> keys = JDKSecurityProperties.getKeys();
+    static String keyValue = "shouldBecomeAnEvent";
+
+    public static void main(String[] args) throws Exception {
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.SecurityProperty);
+            recording.start();
+            for (String key: keys) {
+                Security.setProperty(key, keyValue);
+            }
+            recording.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Asserts.assertEquals(events.size(), keys.size(),
+                    "Incorrect number of events");
+            assertEvent(events);
+        }
+    }
+
+    private static void assertEvent(List<RecordedEvent> events) throws Exception {
+        int i = 1;
+        for (RecordedEvent e : events) {
+            if (keys.contains(e.getString("key"))) {
+                Events.assertField(e, "value").equal(keyValue);
+                i++;
+            } else {
+                System.out.println(events);
+                throw new Exception("Unexpected event at index:" + i);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/security/TestTLSHandshakeEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.event.security;
+
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.security.TestTLSHandshake;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.security.TestTLSHandshakeEvent
+ */
+public class TestTLSHandshakeEvent {
+    public static void main(String[] args) throws Exception {
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.TLSHandshake);
+            recording.start();
+            TestTLSHandshake handshake = new TestTLSHandshake();
+            handshake.run();
+            recording.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Events.hasEvents(events);
+            assertEvent(events, handshake);
+        }
+    }
+
+    private static void assertEvent(List<RecordedEvent> events, TestTLSHandshake handshake) throws Exception {
+        System.out.println(events);
+        for (RecordedEvent e : events) {
+            if (handshake.peerHost.equals(e.getString("peerHost"))) {
+                Events.assertField(e, "peerPort").equal(handshake.peerPort);
+                Events.assertField(e, "protocolVersion").equal(handshake.protocolVersion);
+                Events.assertField(e, "certificateId").equal(TestTLSHandshake.HASHCODE);
+                Events.assertField(e, "cipherSuite").equal(TestTLSHandshake.CIPHER_SUITE);
+                return;
+            }
+        }
+        System.out.println(events);
+        throw new Exception("Could not find event with hostname: " + handshake.peerHost);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/security/TestX509CertificateEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.event.security;
+
+import java.security.cert.CertificateFactory;
+import java.util.List;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.security.TestCertificate;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @key jfr
+ * @library /test/lib
+ * @run main/othervm jdk.jfr.event.security.TestX509CertificateEvent
+ */
+public class TestX509CertificateEvent {
+    public static void main(String[] args) throws Exception {
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.X509Certificate);
+            recording.start();
+
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            TestCertificate.ONE.generate(cf);
+            TestCertificate.TWO.generate(cf);
+            // Generate twice to make sure only one event per certificate is generated
+            TestCertificate.ONE.generate(cf);
+            TestCertificate.TWO.generate(cf);
+
+            recording.stop();
+
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Asserts.assertEquals(events.size(), 2, "Incorrect number of X509Certificate events");
+            assertEvent(events, TestCertificate.ONE);
+            assertEvent(events, TestCertificate.TWO);
+        }
+    }
+
+    private static void assertEvent(List<RecordedEvent> events, TestCertificate cert) throws Exception {
+        for (RecordedEvent e : events) {
+            if (e.getLong("certificateId") == cert.certId) {
+                Events.assertField(e, "algorithm").equal(cert.algorithm);
+                Events.assertField(e, "subject").equal(cert.subject);
+                Events.assertField(e, "issuer").equal(cert.issuer);
+                Events.assertField(e, "keyType").equal(cert.keyType);
+                Events.assertField(e, "keyLength").equal(cert.keyLength);
+                Events.assertField(e, "serialNumber").equal(cert.serialNumber);
+                return;
+            }
+        }
+        System.out.println(events);
+        throw new Exception("Could not find event with cert Id: " + cert.certId);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/jfr/event/security/TestX509ValidationEvent.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+package jdk.jfr.event.security;
+
+import java.util.List;
+
+import jdk.jfr.AnnotationElement;
+import jdk.jfr.EventType;
+import jdk.jfr.FlightRecorder;
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordedEvent;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.jfr.Events;
+import jdk.test.lib.jfr.EventNames;
+import jdk.test.lib.security.TestCertificate;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @key jfr
+ * @library /test/lib
+ * @modules jdk.jfr/jdk.jfr.events
+ * @run main/othervm jdk.jfr.event.security.TestX509ValidationEvent
+ */
+public class TestX509ValidationEvent {
+    public static void main(String[] args) throws Exception {
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.X509Validation);
+            recording.start();
+            // intermeditate certificate test
+            TestCertificate.generateChain(false);
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Asserts.assertEquals(events.size(), 3, "Incorrect number of events");
+            assertEvent1(events);
+        }
+
+        try (Recording recording = new Recording()) {
+            recording.enable(EventNames.X509Validation);
+            recording.start();
+            // self signed certificate test
+            TestCertificate.generateChain(true);
+            recording.stop();
+            List<RecordedEvent> events = Events.fromRecording(recording);
+            Asserts.assertEquals(events.size(), 2, "Incorrect number of events");
+            assertEvent2(events);
+        }
+    }
+
+    private static void assertEvent1(List<RecordedEvent> events) throws Exception {
+        for (RecordedEvent e : events) {
+            int pos = e.getInt("certificatePosition");
+            switch (pos) {
+                case 1:
+                    Events.assertField(e, "certificateId")
+                            .equal(TestCertificate.ROOT_CA.certId);
+                    break;
+                case 2:
+                    Events.assertField(e, "certificateId")
+                            .equal(TestCertificate.TWO.certId);
+                    break;
+                case 3:
+                    Events.assertField(e, "certificateId")
+                            .equal(TestCertificate.ONE.certId);
+                    break;
+                default:
+                    System.out.println(events);
+                    throw new Exception("Unexpected position:" + pos);
+            }
+        }
+    }
+
+    /*
+     * Self signed certificate test
+     */
+    private static void assertEvent2(List<RecordedEvent> events) throws Exception {
+        for (RecordedEvent e : events) {
+            int pos = e.getInt("certificatePosition");
+            switch (pos) {
+                case 1:
+                case 2:
+                    Events.assertField(e, "certificateId")
+                            .equal(TestCertificate.ROOT_CA.certId);
+                    break;
+                default:
+                    System.out.println(events);
+                    throw new Exception("Unexpected position:" + pos);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/security/logging/LogJvm.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+package jdk.security.logging;
+
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public final class LogJvm {
+    private final static String LOGGING_ENABLED= "LOGGING_ENABLED";
+    private final static String LOGGING_DISABLED= "LOGGING_DISABLED";
+
+    private final static boolean debug = false;
+
+    private final List<String> expectedLogMessages = new ArrayList<>();
+    private final Class<?> clazz;
+    private final boolean loggingEnabled;
+
+    public LogJvm(Class<?> clazz, String[] args) {
+        this.clazz = clazz;
+        this.loggingEnabled = Arrays.asList(args).contains(LOGGING_ENABLED);
+        ensureLogging(args);
+    }
+
+    private void ensureLogging(String[] args) {
+        for(String s : args) {
+            if (s.equals(LOGGING_ENABLED) || s.equals(LOGGING_DISABLED)) {
+                return;
+            }
+        }
+        throw new RuntimeException(LogJvm.class.getName() +
+            " requires command line parameter " + LOGGING_ENABLED +
+            " or " + LOGGING_DISABLED);
+    }
+
+    public void addExpected(String logMsg) {
+        expectedLogMessages.add(logMsg);
+    }
+
+    public void testExpected() throws Exception {
+        OutputAnalyzer out = launchJVM();
+        if (debug) {
+            System.out.println("STDOUT DEBUG:\n " + out.getStdout());
+            System.out.println("\nSTDERR DEBUG:\n " + out.getStderr());
+        }
+        if (loggingEnabled) {
+            testLoggingEnabled(out);
+        } else {
+            testLoggingDisabled(out);
+        }
+    }
+
+    public OutputAnalyzer launchJVM() throws Exception {
+        List<String> args = new ArrayList<>();
+        if (loggingEnabled) {
+            args.add("-Djava.util.logging.config.file=" +
+                Paths.get(System.getProperty("test.src", "."), "logging.properties"));
+        }
+        args.add("--add-exports");
+        args.add("java.base/jdk.internal.event=ALL-UNNAMED");
+        args.add(clazz.getName());
+        System.out.println(args);
+        OutputAnalyzer out = ProcessTools.executeTestJava(args.toArray(new String[0]));
+        out.shouldHaveExitValue(0);
+        return out;
+    }
+
+    private void testLoggingDisabled(OutputAnalyzer out) {
+        for (String expected : expectedLogMessages) {
+            out.shouldNotContain(expected);
+        }
+    }
+
+    private void testLoggingEnabled(OutputAnalyzer out) {
+        for (String expected : expectedLogMessages) {
+            out.shouldContain(expected);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/security/logging/TestSecurityPropertyModificationLog.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package jdk.security.logging;
+
+import java.security.Security;
+import java.util.List;
+
+import jdk.test.lib.security.JDKSecurityProperties;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.security.logging.TestSecurityPropertyModificationLog LOGGING_ENABLED
+ * @run main/othervm jdk.security.logging.TestSecurityPropertyModificationLog LOGGING_DISABLED
+ */
+public class TestSecurityPropertyModificationLog {
+
+    static List<String> keys = JDKSecurityProperties.getKeys();
+    static String keyValue = "shouldBecomeAnEvent";
+
+    public static void main(String[] args) throws Exception {
+        LogJvm l = new LogJvm(SetSecurityProperty.class, args);
+        for (String s: keys) {
+            l.addExpected("FINE: SecurityPropertyModification: key:" +
+                    s + ", value:" + keyValue);
+        }
+        l.testExpected();
+    }
+
+    public static class SetSecurityProperty {
+        public static void main(String[] args) {
+            for (String s: keys) {
+                Security.setProperty(s, keyValue);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/security/logging/TestTLSHandshakeLog.java	Tue Nov 20 13:12:48 2018 +0000
@@ -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.
+ */
+
+package jdk.security.logging;
+
+import jdk.test.lib.security.TestTLSHandshake;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.security.logging.TestTLSHandshakeLog LOGGING_ENABLED
+ * @run main/othervm jdk.security.logging.TestTLSHandshakeLog LOGGING_DISABLED
+ */
+public class TestTLSHandshakeLog {
+    public static void main(String[] args) throws Exception {
+        LogJvm l = new LogJvm(TLSHandshake.class, args);
+        l.addExpected("FINE: X509Certificate: Alg:SHA256withRSA, Serial:" + TestTLSHandshake.CERT_SERIAL);
+        l.addExpected("Subject:CN=Regression Test");
+        l.addExpected("Key type:EC, Length:256");
+        l.addExpected("FINE: ValidationChain: " +
+                TestTLSHandshake.ANCHOR_HASHCODE +
+                ", " + TestTLSHandshake.HASHCODE);
+        l.addExpected("SunJSSE Test Serivce");
+        l.addExpected("TLSHandshake:");
+        l.addExpected("TLSv1.2");
+        l.addExpected(TestTLSHandshake.CIPHER_SUITE +", " + TestTLSHandshake.HASHCODE);
+        l.testExpected();
+    }
+
+    public static class TLSHandshake {
+        public static void main(String[] args) throws Exception {
+            TestTLSHandshake handshake = new TestTLSHandshake();
+            handshake.run();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/security/logging/TestX509CertificateLog.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+package jdk.security.logging;
+
+import java.security.cert.CertificateFactory;
+import jdk.test.lib.security.TestCertificate;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.security.logging.TestX509CertificateLog LOGGING_ENABLED
+ * @run main/othervm jdk.security.logging.TestX509CertificateLog LOGGING_DISABLED
+ */
+public class TestX509CertificateLog {
+    public static void main(String[] args) throws Exception {
+        LogJvm l = new LogJvm(GenerateX509Certicate.class, args);
+        l.addExpected(
+            "FINE: X509Certificate: Alg:" + TestCertificate.ONE.algorithm +
+            ", Serial:" + TestCertificate.ONE.serialNumber +
+            ", Subject:" + TestCertificate.ONE.subject +
+            ", Issuer:"  + TestCertificate.ONE.issuer +
+            ", Key type:" + TestCertificate.ONE.keyType +
+            ", Length:" + TestCertificate.ONE.keyLength +
+            ", Cert Id:" + TestCertificate.ONE.certId);
+        l.addExpected(
+            "FINE: X509Certificate: Alg:" + TestCertificate.TWO.algorithm +
+            ", Serial:" + TestCertificate.TWO.serialNumber +
+            ", Subject:" + TestCertificate.TWO.subject +
+            ", Issuer:"  + TestCertificate.TWO.issuer +
+            ", Key type:" + TestCertificate.TWO.keyType +
+            ", Length:" + TestCertificate.TWO.keyLength +
+            ", Cert Id:" + TestCertificate.TWO.certId);
+        l.testExpected();
+    }
+
+    public static class GenerateX509Certicate {
+        public static void main(String[] args) throws Exception {
+            CertificateFactory cf = CertificateFactory.getInstance("X.509");
+            TestCertificate.ONE.generate(cf);
+            TestCertificate.TWO.generate(cf);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/security/logging/TestX509ValidationLog.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package jdk.security.logging;
+
+import jdk.test.lib.security.TestCertificate;
+
+/*
+ * @test
+ * @bug 8148188
+ * @summary Enhance the security libraries to record events of interest
+ * @library /test/lib /test/jdk
+ * @run main/othervm jdk.security.logging.TestX509ValidationLog LOGGING_ENABLED
+ * @run main/othervm jdk.security.logging.TestX509ValidationLog LOGGING_DISABLED
+ */
+public class TestX509ValidationLog {
+    public static void main(String[] args) throws Exception {
+        LogJvm l = new LogJvm(GenerateCertificateChain.class, args);
+        l.addExpected("FINE: ValidationChain: " +
+                TestCertificate.ROOT_CA.certId + ", " +
+                TestCertificate.TWO.certId + ", " +
+                TestCertificate.ONE.certId);
+        l.addExpected("FINE: ValidationChain: " +
+                TestCertificate.ROOT_CA.certId + ", " +
+                TestCertificate.ROOT_CA.certId);
+        l.testExpected();
+    }
+
+    public static class GenerateCertificateChain {
+        public static void main(String[] args) throws Exception {
+            TestCertificate.generateChain(false);
+            // self signed test
+            TestCertificate.generateChain(true);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/security/logging/logging.properties	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,13 @@
+############################################################
+#  	Configuration file for log testing
+#
+############################################################
+
+handlers= java.util.logging.ConsoleHandler
+
+.level= FINE
+
+java.util.logging.ConsoleHandler.level = FINE
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+jdk.event.security.level = FINE
--- a/test/lib/jdk/test/lib/jfr/EventNames.java	Tue Nov 20 10:08:19 2018 +0100
+++ b/test/lib/jdk/test/lib/jfr/EventNames.java	Tue Nov 20 13:12:48 2018 +0000
@@ -169,6 +169,10 @@
     public final static String JavaErrorThrow = PREFIX + "JavaErrorThrow";
     public final static String ModuleRequire = PREFIX + "ModuleRequire";
     public final static String ModuleExport = PREFIX + "ModuleExport";
+    public final static String TLSHandshake = PREFIX + "TLSHandshake";
+    public final static String X509Certificate = PREFIX + "X509Certificate";
+    public final static String X509Validation = PREFIX + "X509Validation";
+    public final static String SecurityProperty = PREFIX + "SecurityPropertyModification";
 
     // Flight Recorder
     public final static String DumpReason = PREFIX + "DumpReason";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/security/JDKSecurityProperties.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package jdk.test.lib.security;
+
+import java.util.List;
+import java.security.Security;
+
+public final class JDKSecurityProperties {
+
+    public static final List<String> jdkProps = List.of(
+        "com.sun.CORBA.ORBIorTypeCheckRegistryFilter",
+        "crypto.policy",
+        "jceks.key.serialFilter",
+        "jdk.certpath.disabledAlgorithms",
+        "keystore.type",
+        "krb5.kdc.bad.policy",
+        "login.config",
+        "networkaddress.cache.ttl",
+        "ocsp.responderURL",
+        "package.access",
+        "policy.allowSystemProperty",
+        "securerandom.drbg.config",
+        "security.provider.1",
+        "ssl.KeyManagerFactory.algorithm",
+        "sun.rmi.registry.registryFilter"
+    );
+
+    public static List getKeys() {
+        return jdkProps;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/security/SSLSocketTest.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,891 @@
+/*
+ * 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.
+ */
+
+package jdk.test.lib.security;
+
+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 up 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 abstract class SSLSocketTest {
+
+    /*
+     * Run the test case.
+     */
+    public void run() throws Exception {
+        bootup();
+    }
+
+    /*
+     * Define the server side application of the test for the specified socket.
+     */
+    protected abstract void runServerApplication(SSLSocket socket) throws Exception;
+
+    /*
+     * 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 abstract void runClientApplication(SSLSocket socket) throws Exception;
+
+    /*
+     * 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/lib/jdk/test/lib/security/TestCertificate.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+package jdk.test.lib.security;
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+// Certificates taken from old ValWithAnchorByName testcase ***
+public enum TestCertificate {
+    // Subject: CN=SSLCertificate, O=SomeCompany
+    // Issuer: CN=Intermediate CA Cert, O=SomeCompany
+    // Validity: Tue Aug 30 14:37:19 PDT 2016 to Wed Aug 30 14:37:19 PDT 2017
+    ONE("1000",
+        "CN=SSLCertificate, O=SomeCompany",
+        "CN=Intermediate CA Cert, O=SomeCompany",
+        -1063259762,
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDnTCCAoWgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwNTEUMBIGA1UEChMLU29t\n" +
+        "ZUNvbXBhbnkxHTAbBgNVBAMTFEludGVybWVkaWF0ZSBDQSBDZXJ0MB4XDTE2MDgz\n" +
+        "MDIxMzcxOVoXDTE3MDgzMDIxMzcxOVowLzEUMBIGA1UEChMLU29tZUNvbXBhbnkx\n" +
+        "FzAVBgNVBAMTDlNTTENlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" +
+        "MIIBCgKCAQEAjgv8KKE4CO0rbCjRLA1hXjRiSq30jeusCJ8frbRG+QOBgQ3j6jgc\n" +
+        "vk5wG1aTu7R4AFn0/HRDMzP9ZbRlZVIbJUTd8YiaNyZeyWapPnxHWrPCd5e1xopk\n" +
+        "ElieDdEH5FiLGtIrWy56CGA1hfQb1vUVYegyeY+TTtMFVHt0PrmMk4ZRgj/GtVNp\n" +
+        "BQQYIzaYAcrcWMeCn30ZrhaGAL1hsdgmEVV1wsTD4JeNMSwLwMYem7fg8ondGZIR\n" +
+        "kZuGtuSdOHu4Xz+mgDNXTeX/Bp/dQFucxCG+FOOM9Hoz72RY2W8YqgL38RlnwYWp\n" +
+        "nUNxhXWFH6vyINRQVEu3IgahR6HXjxM7LwIDAQABo4G8MIG5MBQGA1UdEQQNMAuC\n" +
+        "CWxvY2FsaG9zdDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9s\n" +
+        "b2NhbGhvc3Q6NDIzMzMwHwYDVR0jBBgwFoAUYT525lwHCI4CmuWs8a7poaeKRJ4w\n" +
+        "HQYDVR0OBBYEFCaQnOX4L1ovqyfeKuoay+kI+lXgMA4GA1UdDwEB/wQEAwIFoDAd\n" +
+        "BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEB\n" +
+        "AD8dqQIqFasJcL8lm4mPTsBl0JgNiN8tQcXM7VCvcH+yDvEyh9vudDjuhpSORqPq\n" +
+        "f1o/EvJ+gfs269mBnYQujYRvmSd6EAcBntv5zn6amOh03o6PqTY9KaUC/mL9hB84\n" +
+        "Y5/LYioP16sME7egKnlrGUgKh0ZvGzm7c3SYx3Z5YoeFBOkZajc7Jm+cBw/uBQkF\n" +
+        "a9mLEczIvOgkq1wto8vr2ptH1gEuvFRcorN3muvq34bk40G08+AHlP3fCLFpI3FA\n" +
+        "IStJLJZRcO+Ib4sOcKuaBGnuMo/QVOCEMDUs6RgiWtSd93OZKFIUOASVp6YIkcSs\n" +
+        "5/rmc06sICqBjLfPEB68Jjw=\n" +
+        "-----END CERTIFICATE-----"),
+    // Subject: CN=Intermediate CA Cert, O=SomeCompany
+    // Issuer: CN=Root CA Cert, O=SomeCompany
+    // Validity: Sun Aug 07 14:37:19 PDT 2016 to Tue Aug 07 14:37:19 PDT 2018
+    TWO("64",
+        "CN=Intermediate CA Cert, O=SomeCompany",
+        "CN=Root CA Cert, O=SomeCompany",
+        -927189373,
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDdjCCAl6gAwIBAgIBZDANBgkqhkiG9w0BAQsFADAtMRQwEgYDVQQKEwtTb21l\n" +
+        "Q29tcGFueTEVMBMGA1UEAxMMUm9vdCBDQSBDZXJ0MB4XDTE2MDgwNzIxMzcxOVoX\n" +
+        "DTE4MDgwNzIxMzcxOVowNTEUMBIGA1UEChMLU29tZUNvbXBhbnkxHTAbBgNVBAMT\n" +
+        "FEludGVybWVkaWF0ZSBDQSBDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n" +
+        "CgKCAQEAnJR5CnE7GKlQjigExSJ6hHu302mc0PcA6TDgsIitPYD/r8RBbBuE51OQ\n" +
+        "7IP7AXmfPUV3/+pO/uxx6mgY5O6XeUl7KadhVPtPcL0BVVevCSOdTMVa3iV4zRpa\n" +
+        "C6Uy2ouUFnafKnDtlbieggyETUoNgVNJYA9L0XNhtSnENoLHC4Pq0v8OsNtsOWFR\n" +
+        "NiMTOA49NNDBw85WgPyFAxjqO4z0J0zxdWq3W4rSMB8xrkulv2Rvj3GcfYJK/ab8\n" +
+        "V1IJ6PMWCpujASY3BzvYPnN7BKuBjbWJPgZdPYfX1cxeG80u0tOuMfWWiNONSMSA\n" +
+        "7m9y304QA0gKqlrFFn9U4hU89kv1IwIDAQABo4GYMIGVMA8GA1UdEwEB/wQFMAMB\n" +
+        "Af8wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vbG9jYWxob3N0\n" +
+        "OjM5MTM0MB8GA1UdIwQYMBaAFJNMsejEyJUB9tiWycVczvpiMVQZMB0GA1UdDgQW\n" +
+        "BBRhPnbmXAcIjgKa5azxrumhp4pEnjAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN\n" +
+        "AQELBQADggEBAE4nOFdW9OirPnRvxihQXYL9CXLuGQz5tr0XgN8wSY6Un9b6CRiK\n" +
+        "7obgIGimVdhvUC1qdRcwJqgOfJ2/jR5/5Qo0TVp+ww4dHNdUoj73tagJ7jTu0ZMz\n" +
+        "5Zdp0uwd4RD/syvTeVcbPc3m4awtgEvRgzpDMcSeKPZWInlo7fbnowKSAUAfO8de\n" +
+        "0cDkxEBkzPIzGNu256cdLZOqOK9wLJ9mQ0zKgi/2NsldNc2pl/6jkGpA6uL5lJsm\n" +
+        "fo9sDusWNHV1YggqjDQ19hrf40VuuC9GFl/qAW3marMuEzY/NiKVUxty1q1s48SO\n" +
+        "g5LoEPDDkbygOt7ICL3HYG1VufhC1Q2YY9c=\n" +
+        "-----END CERTIFICATE-----"),
+    // Subject: CN=Root CA Cert, O=SomeCompany
+    // Issuer: CN=Root CA Cert, O=SomeCompany
+    // Validity: Fri Jul 08 14:37:18 PDT 2016 to Fri Jun 28 14:37:18 PDT 2019
+    ROOT_CA("1",
+        "CN=Root CA Cert, O=SomeCompany",
+        "CN=Root CA Cert, O=SomeCompany",
+        -1299818863,
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIDODCCAiCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMRQwEgYDVQQKEwtTb21l\n" +
+        "Q29tcGFueTEVMBMGA1UEAxMMUm9vdCBDQSBDZXJ0MB4XDTE2MDcwODIxMzcxOFoX\n" +
+        "DTE5MDYyODIxMzcxOFowLTEUMBIGA1UEChMLU29tZUNvbXBhbnkxFTATBgNVBAMT\n" +
+        "DFJvb3QgQ0EgQ2VydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIlN\n" +
+        "M3WYEqkU2elXEZrV9QSDbDKwyaLEHafLFciH8Edoag3q/7jEzFJxI7JZ831tdbWQ\n" +
+        "Bm6Hgo+8pvetOFW1BckL8eIjyOONP2CKfFaeMaozsWi1cgxa+rjpU/Rekc+zBqvv\n" +
+        "y4Sr97TwT6nQiLlgjC1nCfR1SVpO51qoDChS7n785rsKEZxw/p+kkVWSZffU7zN9\n" +
+        "c645cPg//L/kjiyeKMkaquGQOYS68gQgy8YZXQv1E3l/8e8Ci1s1DYA5wpCbaBqg\n" +
+        "Tw84Rr4zlUEQBgXzQlRt+mPzeaDpdG1EeGkXrcdkZ+0EMELoOVXOEn6VNsz6vT3I\n" +
+        "KrnvQBSnN06xq/iWwC0CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME\n" +
+        "GDAWgBSTTLHoxMiVAfbYlsnFXM76YjFUGTAdBgNVHQ4EFgQUk0yx6MTIlQH22JbJ\n" +
+        "xVzO+mIxVBkwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAAi+Nl\n" +
+        "sxP9t2IhiZIHRJGSBZuQlXIjwYIwbq3ZWc/ApZ+0oxtl7DYQi5uRNt8/opcGNCHc\n" +
+        "IY0fG93SbkDubXbxPYBW6D/RUjbz59ZryaP5ym55p1MjHTOqy+AM8g41xNTJikc3\n" +
+        "UUFXXnckeFbawijCsb7vf71owzKuxgBXi9n1rmXXtncKoA/LrUVXoUlKefdgDnsU\n" +
+        "sl3Q29eibE3HSqziMMoAOLm0jjekFGWIgLeTtyRYR1d0dNaUwsHTrQpPjxxUTn1x\n" +
+        "sAPpXKfzPnsYAZeeiaaE75GwbWlHzrNinvxdZQd0zctpfBJfVqD/+lWANlw+rOaK\n" +
+        "J2GyCaJINsyaI/I2\n" +
+        "-----END CERTIFICATE-----");
+
+    public String serialNumber;
+    public String algorithm;
+    public String subject;
+    public String issuer;
+    public String keyType;
+    public long certId;
+    public int keyLength;
+    public String encoded;
+
+    TestCertificate(String serialNumber, String subject, String issuer,
+                    long certId, String encoded) {
+        this.serialNumber = serialNumber;
+        this.subject = subject;
+        this.issuer = issuer;
+        this.algorithm = "SHA256withRSA";
+        this.encoded = encoded;
+        this.certId = certId;
+        this.keyType = "RSA";
+        this.keyLength = 2048;
+    }
+
+    public X509Certificate generate(CertificateFactory cf) throws CertificateException {
+        ByteArrayInputStream is = new ByteArrayInputStream(encoded.getBytes());
+        return (X509Certificate) cf.generateCertificate(is);
+    }
+
+    public static void generateChain(boolean selfSignedTest) throws Exception {
+        // Do path validation as if it is always Tue, 06 Sep 2016 22:12:21 GMT
+        // This value is within the lifetimes of all certificates.
+        Date testDate = new Date(1473199941000L);
+
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        X509Certificate c1 = TestCertificate.ONE.generate(cf);
+        X509Certificate c2 = TestCertificate.TWO.generate(cf);
+        X509Certificate ca = TestCertificate.ROOT_CA.generate(cf);
+
+        TrustAnchor ta = new TrustAnchor(ca, null);
+        CertPathValidator validator = CertPathValidator.getInstance("PKIX");
+
+        PKIXParameters params = new PKIXParameters(Collections.singleton(ta));
+        params.setRevocationEnabled(false);
+        params.setDate(testDate);
+        if (!selfSignedTest) {
+            CertPath path = cf.generateCertPath(List.of(c1, c2));
+            validator.validate(path, params);
+        } else {
+            CertPath path = cf.generateCertPath(List.of(ca));
+            validator.validate(path, params);
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/lib/jdk/test/lib/security/TestTLSHandshake.java	Tue Nov 20 13:12:48 2018 +0000
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+package jdk.test.lib.security;
+
+import java.io.*;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+
+public final class TestTLSHandshake extends SSLSocketTest {
+
+    public static final String CIPHER_SUITE =
+        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
+    public static final long HASHCODE = -1057291798L;
+    public static final long ANCHOR_HASHCODE = 1688661792L;
+    public static final String CERT_SERIAL = "edbec8f705af2514";
+    public static final String ANCHOR_CERT_SERIAL = "8e191778b2f331be";
+
+    public String protocolVersion;
+    public String peerHost;
+    public int peerPort;
+
+    @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 {
+        socket.setEnabledCipherSuites(new String[] { CIPHER_SUITE });
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        SSLSession sslSession = socket.getSession();
+        protocolVersion =  sslSession.getProtocol();
+        peerHost = sslSession.getPeerHost();
+        peerPort = sslSession.getPeerPort();
+    }
+}