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: mbaesken
Backport-of: 102b2b32feec4727145be4814eb1a69ef462ff16
  • Loading branch information
GoeLin committed Jan 24, 2023
1 parent 0056a63 commit eac9a05
Show file tree
Hide file tree
Showing 12 changed files with 183 additions and 84 deletions.
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
@@ -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
46 changes: 46 additions & 0 deletions src/java.base/share/classes/sun/security/jca/JCAUtil.java
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 @@ -91,6 +98,45 @@ public static SecureRandom getDefSecureRandom() {
}
}
return result;
}

public static void tryCommitCertEvent(Certificate cert) {
if ((X509CertificateEvent.isTurnedOn() || EventHelper.isLoggingSecurity()) &&
(cert instanceof X509Certificate x509)) {
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);
}
}
}
}
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 @@ -767,43 +762,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);
}
}
}
}
Expand Up @@ -355,7 +355,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
@@ -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
Expand Up @@ -41,6 +41,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
@@ -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
Expand Up @@ -39,7 +39,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
@@ -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
@@ -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

1 comment on commit eac9a05

@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.