mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8148188: Enhance the security libraries to record events of interest
Reviewed-by: egahlin, mullan, weijun, xuelei
This commit is contained in:
parent
dc260a5369
commit
73ad9c4a00
35 changed files with 2617 additions and 8 deletions
|
@ -30,6 +30,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
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 @@ public final class Security {
|
|||
* @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);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
126
src/java.base/share/classes/jdk/internal/event/EventHelper.java
Normal file
126
src/java.base/share/classes/jdk/internal/event/EventHelper.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 @@ public class X509Factory extends CertificateFactorySpi {
|
|||
}
|
||||
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 @@ public class X509Factory extends CertificateFactorySpi {
|
|||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,10 @@ import java.io.IOException;
|
|||
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 @@ import sun.security.util.Debug;
|
|||
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 @@ public final class PKIXCertPathValidator extends CertPathValidatorSpi {
|
|||
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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ import javax.crypto.Mac;
|
|||
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 @@ final class Finished {
|
|||
|
||||
// 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 @@ final class Finished {
|
|||
|
||||
// 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 @@ final class Finished {
|
|||
// 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 @@ final class Finished {
|
|||
if (!shc.sslContext.isDTLS()) {
|
||||
shc.conContext.finishHandshake();
|
||||
}
|
||||
recordEvent(shc.conContext.conSession);
|
||||
|
||||
//
|
||||
// produce
|
||||
|
@ -1074,4 +1083,35 @@ final class Finished {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue