Skip to content

Commit

Permalink
8280890: Cannot use '-Djava.system.class.loader' with class loader in…
Browse files Browse the repository at this point in the history
… signed JAR

Reviewed-by: andrew
Backport-of: a0f6f2409ea61ff9ed9dc2e2b46e309c751d456d
  • Loading branch information
jerboaa committed Dec 23, 2022
1 parent c961cb9 commit ebc5e19
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 31 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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 @@ -39,9 +39,12 @@
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
Expand All @@ -52,7 +55,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

Expand Down Expand Up @@ -686,41 +688,30 @@ public void permits(ConstraintsParameters cp)
* timezone.
*/
private static class DenyAfterConstraint extends Constraint {
private Date denyAfterDate;
private ZonedDateTime zdt;
private Instant denyAfterDate;

DenyAfterConstraint(String algo, int year, int month, int day) {
Calendar c;

algorithm = algo;

if (debug != null) {
debug.println("DenyAfterConstraint read in as: year " +
debug.println("DenyAfterConstraint read in as: year " +
year + ", month = " + month + ", day = " + day);
}

c = new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("GMT"))
.setDate(year, month - 1, day).build();

if (year > c.getActualMaximum(Calendar.YEAR) ||
year < c.getActualMinimum(Calendar.YEAR)) {
throw new IllegalArgumentException(
"Invalid year given in constraint: " + year);
}
if ((month - 1) > c.getActualMaximum(Calendar.MONTH) ||
(month - 1) < c.getActualMinimum(Calendar.MONTH)) {
throw new IllegalArgumentException(
"Invalid month given in constraint: " + month);
}
if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) ||
day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) {
try {
zdt = ZonedDateTime
.of(year, month, day, 0, 0, 0, 0, ZoneId.of("GMT"));
denyAfterDate = zdt.toInstant();
} catch (DateTimeException dte) {
throw new IllegalArgumentException(
"Invalid Day of Month given in constraint: " + day);
"Invalid denyAfter date", dte);
}

denyAfterDate = c.getTime();
if (debug != null) {
debug.println("DenyAfterConstraint date set to: " +
denyAfterDate);
zdt.toLocalDate());
}
}

Expand All @@ -735,23 +726,22 @@ private static class DenyAfterConstraint extends Constraint {
@Override
public void permits(ConstraintsParameters cp)
throws CertPathValidatorException {
Date currentDate;
String errmsg;
Instant currentDate;

if (cp.getDate() != null) {
currentDate = cp.getDate();
currentDate = cp.getDate().toInstant();
} else {
currentDate = new Date();
currentDate = Instant.now();
}

if (!denyAfterDate.after(currentDate)) {
if (!denyAfterDate.isAfter(currentDate)) {
if (next(cp)) {
return;
}
throw new CertPathValidatorException(
"denyAfter constraint check failed: " + algorithm +
" used with Constraint date: " +
denyAfterDate + "; params date: " +
zdt.toLocalDate() + "; params date: " +
currentDate + cp.extendedExceptionMsg(),
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
}
Expand All @@ -770,7 +760,7 @@ public boolean permits(Key key) {
debug.println("DenyAfterConstraints.permits(): " + algorithm);
}

return denyAfterDate.after(new Date());
return denyAfterDate.isAfter(Instant.now());
}
}

Expand Down
44 changes: 44 additions & 0 deletions jdk/test/java/security/SignedJar/CustomClassLoader.java
@@ -0,0 +1,44 @@
/*
* Copyright (c) 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
* 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.
*/

import java.io.IOException;
import java.io.InputStream;
import sun.misc.IOUtils;

public class CustomClassLoader extends ClassLoader {

public CustomClassLoader(ClassLoader parent) {
super(parent);
}

@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
try (InputStream is = getClass().getClassLoader()
.getResourceAsStream(name + ".class")) {
byte[] buf = IOUtils.readAllBytes(is);
return defineClass(name, buf, 0, buf.length);
} catch (IOException e) {
throw new ClassNotFoundException(e.getMessage());
}
}
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) 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
* 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.
*/

/**
* @test
* @bug 8280890
* @library /lib/testlibrary
* @build SignedJarWithCustomClassLoader CustomClassLoader
* @run main/othervm SignedJarWithCustomClassLoader
* @summary Make sure java.system.class.loader property can be used when custom
* class loader is inside signed jar
*/

import java.nio.file.Path;
import java.nio.file.Paths;

import jdk.testlibrary.SecurityTools;
import jdk.testlibrary.InMemoryJavaCompiler;
import jdk.testlibrary.ProcessTools;
import jdk.testlibrary.JarUtils;

public class SignedJarWithCustomClassLoader {

public static void main(String[] args) throws Throwable {

// compile the Main program
String main = "public class Main {\n" +
" public static void main(String[] args) {}\n" +
"}\n";
String testClasses = System.getProperty("test.classes", "");
ClassFileInstaller.writeClassToDisk("Main",
InMemoryJavaCompiler.compile("Main", main),
testClasses);

// create the jar file
Path classes = Paths.get(testClasses);
JarUtils.createJarFile(Paths.get("test.jar"), classes,
classes.resolve("CustomClassLoader.class"),
classes.resolve("Main.class"));

// create signer's keypair
SecurityTools.keytool("-genkeypair -keyalg RSA -keystore ks " +
"-storepass changeit -dname CN=test -alias test")
.shouldHaveExitValue(0);

// sign jar
SecurityTools.jarsigner("-keystore ks -storepass changeit " +
"-signedjar signed.jar test.jar test")
.shouldHaveExitValue(0);

// run app with system class loader set to custom classloader
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-cp", "signed.jar",
"-Djava.system.class.loader=CustomClassLoader", "Main");
ProcessTools.executeProcess(pb)
.shouldHaveExitValue(0);

// sign jar again, but this time with SHA-1 which is disabled
SecurityTools.jarsigner("-keystore ks -storepass changeit " +
"-digestalg SHA-1 -sigalg SHA1withRSA " +
"-signedjar signed.jar test.jar test")
.shouldHaveExitValue(0);

// run app again, should still succeed even though SHA-1 is disabled
pb = ProcessTools.createJavaProcessBuilder(
"-cp", "signed.jar",
"-Djava.system.class.loader=CustomClassLoader", "Main");
ProcessTools.executeProcess(pb)
.shouldHaveExitValue(0);
}
}

1 comment on commit ebc5e19

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