8148188: Enhance the security libraries to record events of interest
Reviewed-by: egahlin, mullan, weijun, xuelei
--- 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();
+ }
+}