Skip to content

Commit

Permalink
8292033: Move jdk.X509Certificate event logic to JCA layer
Browse files Browse the repository at this point in the history
Reviewed-by: lucy
Backport-of: 102b2b32feec4727145be4814eb1a69ef462ff16
  • Loading branch information
GoeLin committed Jun 25, 2023
1 parent b2e04df commit e0b98bc
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
package java.security.cert;

import java.io.InputStream;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.security.Provider;
import java.security.Security;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
Expand Down Expand Up @@ -352,7 +352,9 @@ public final String getType() {
public final Certificate generateCertificate(InputStream inStream)
throws CertificateException
{
return certFacSpi.engineGenerateCertificate(inStream);
Certificate c = certFacSpi.engineGenerateCertificate(inStream);
JCAUtil.tryCommitCertEvent(c);
return c;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -31,6 +31,15 @@
*/

public final class X509CertificateEvent extends Event {
private static final X509CertificateEvent EVENT = new X509CertificateEvent();

/**
* Returns {@code true} if event is enabled, {@code false} otherwise.
*/
public static boolean isTurnedOn() {
return EVENT.isEnabled();
}

public String algorithm;
public String serialNumber;
public String subject;
Expand Down
49 changes: 49 additions & 0 deletions src/java.base/share/classes/sun/security/jca/JCAUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@

import java.lang.ref.*;
import java.security.*;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import jdk.internal.event.EventHelper;
import jdk.internal.event.X509CertificateEvent;
import sun.security.util.KeyUtil;

/**
* Collection of static utility methods used by the security framework.
Expand Down Expand Up @@ -93,4 +100,46 @@ public static SecureRandom getDefSecureRandom() {
return result;

}

public static void tryCommitCertEvent(Certificate cert) {
if ((X509CertificateEvent.isTurnedOn() || EventHelper.isLoggingSecurity())) {
if (cert instanceof X509Certificate) {
X509Certificate x509 = (X509Certificate) cert;
PublicKey pKey = x509.getPublicKey();
String algId = x509.getSigAlgName();
String serNum = x509.getSerialNumber().toString(16);
String subject = x509.getSubjectX500Principal().toString();
String issuer = x509.getIssuerX500Principal().toString();
String keyType = pKey.getAlgorithm();
int length = KeyUtil.getKeySize(pKey);
int hashCode = x509.hashCode();
long beginDate = x509.getNotBefore().getTime();
long endDate = x509.getNotAfter().getTime();
if (X509CertificateEvent.isTurnedOn()) {
X509CertificateEvent xce = new X509CertificateEvent();
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);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,9 @@
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.*;
Expand Down Expand Up @@ -104,8 +101,6 @@ public Certificate engineGenerateCertificate(InputStream is)
}
cert = new X509CertImpl(encoding);
addToCache(certCache, cert.getEncodedInternal(), cert);
// record cert details if necessary
commitEvent(cert);
return cert;
} else {
throw new IOException("Empty input");
Expand Down Expand Up @@ -473,7 +468,7 @@ public Collection<? extends java.security.cert.CRL> engineGenerateCRLs(
}
} catch (ParsingException e) {
while (data != null) {
coll.add(new X509CertImpl(data));
coll.add(X509CertImpl.newX509CertImpl(data));
data = readOneBlock(pbis);
}
}
Expand Down Expand Up @@ -766,43 +761,4 @@ private static int readBERInternal(InputStream is,
}
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);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ public OCSPResponse(byte[] bytes) throws IOException {
try {
for (int i = 0; i < derCerts.length; i++) {
X509CertImpl cert =
new X509CertImpl(derCerts[i].toByteArray());
X509CertImpl.newX509CertImpl(derCerts[i].toByteArray());
certs.add(cert);

if (debug != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -240,7 +240,7 @@ private void parse(DerValue val)
}
opt = opt.data.getDerValue();
forward = X509Factory.intern
(new X509CertImpl(opt.toByteArray()));
(X509CertImpl.newX509CertImpl(opt.toByteArray()));
}
break;
case TAG_REVERSE:
Expand All @@ -251,7 +251,7 @@ private void parse(DerValue val)
}
opt = opt.data.getDerValue();
reverse = X509Factory.intern
(new X509CertImpl(opt.toByteArray()));
(X509CertImpl.newX509CertImpl(opt.toByteArray()));
}
break;
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

import javax.security.auth.x500.X500Principal;

import sun.security.jca.JCAUtil;
import sun.security.util.*;
import sun.security.provider.X509Factory;

Expand Down Expand Up @@ -304,6 +305,13 @@ public X509CertImpl(DerValue derVal) throws CertificateException {
}
}

// helper method to record certificate, if necessary, after construction
public static X509CertImpl newX509CertImpl(byte[] certData) throws CertificateException {
var cert = new X509CertImpl(certData);
JCAUtil.tryCommitCertEvent(cert);
return cert;
}

/**
* Appends the certificate to an output stream.
*
Expand Down
53 changes: 40 additions & 13 deletions test/jdk/jdk/jfr/event/security/TestX509CertificateEvent.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -23,43 +23,70 @@

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.jfr.VoidFunction;
import jdk.test.lib.security.TestCertificate;

/*
* @test
* @bug 8148188
* @bug 8148188 8292033
* @summary Enhance the security libraries to record events of interest
* @key jfr
* @requires vm.hasJFR
* @modules java.base/sun.security.x509 java.base/sun.security.tools.keytool
* @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();

public static void main(String[] args) throws Throwable {
testCall(() -> {
// test regular cert construction
TestCertificate.ONE.certificate();
TestCertificate.TWO.certificate();
// Generate twice to make sure only one event per certificate is generated
// Generate twice to make sure we (now) capture all generate cert events
TestCertificate.ONE.certificate();
TestCertificate.TWO.certificate();
}, 4, true);

recording.stop();
testCall(() -> {
// test generateCertificates method
TestCertificate.certificates();
}, 2, true);

testCall(() -> {
// test generateCertPath method
TestCertificate.certPath();
}, 4, true);

testCall(() -> {
// test keytool cert generation with JFR enabled
// The keytool test will load the dedicated keystore
// and call CertificateFactory.generateCertificate
// cacerts
TestCertificate.keyToolTest();
}, -1, false);
}

private static void testCall(VoidFunction f, int expected, boolean runAsserts) throws Throwable {
try (Recording recording = new Recording()) {
recording.enable(EventNames.X509Certificate);
recording.start();
f.run();
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);
if (expected >= 0) {
Asserts.assertEquals(events.size(), expected, "Incorrect number of events");
}
if (runAsserts) {
assertEvent(events, TestCertificate.ONE);
assertEvent(events, TestCertificate.TWO);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* @key jfr
* @requires vm.hasJFR
* @library /test/lib
* @modules jdk.jfr/jdk.jfr.events
* @modules jdk.jfr/jdk.jfr.events java.base/sun.security.x509 java.base/sun.security.tools.keytool
* @run main/othervm jdk.jfr.event.security.TestX509ValidationEvent
*/
public class TestX509ValidationEvent {
Expand Down
4 changes: 2 additions & 2 deletions test/jdk/jdk/security/logging/TestX509CertificateLog.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -23,14 +23,14 @@

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
* @modules java.base/sun.security.x509 java.base/sun.security.tools.keytool
* @run main/othervm jdk.security.logging.TestX509CertificateLog LOGGING_ENABLED
* @run main/othervm jdk.security.logging.TestX509CertificateLog LOGGING_DISABLED
*/
Expand Down
3 changes: 2 additions & 1 deletion test/jdk/jdk/security/logging/TestX509ValidationLog.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -30,6 +30,7 @@
* @bug 8148188
* @summary Enhance the security libraries to record events of interest
* @library /test/lib /test/jdk
* @modules java.base/sun.security.x509 java.base/sun.security.tools.keytool
* @run main/othervm jdk.security.logging.TestX509ValidationLog LOGGING_ENABLED
* @run main/othervm jdk.security.logging.TestX509ValidationLog LOGGING_DISABLED
*/
Expand Down
Loading

1 comment on commit e0b98bc

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.