8280890: Cannot use '-Djava.system.class.loader' with class loader in signed JAR

Reviewed-by: weijun, hchao
This commit is contained in:
Sean Mullan 2022-02-07 14:06:08 +00:00
parent 22a1a32c7e
commit a0f6f2409e
4 changed files with 158 additions and 44 deletions

View File

@ -47,8 +47,6 @@ import java.security.interfaces.EdECKey;
import java.security.spec.ECParameterSpec;
import java.text.Collator;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.BiFunction;
import java.util.jar.JarEntry;
@ -4926,17 +4924,6 @@ public final class Main {
"Unable.to.parse.denyAfter.string.in.exception.message"));
}
SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
Date dateObj = null;
try {
dateObj = formatter.parse(denyAfterDate);
} catch (ParseException e2) {
throw new Exception(rb.getString(
"Unable.to.parse.denyAfter.string.in.exception.message"));
}
formatter = new SimpleDateFormat("yyyy-MM-dd");
denyAfterDate = formatter.format(dateObj);
weakWarnings.add(String.format(
rb.getString("whose.sigalg.usagesignedjar"), label, sigAlg,
denyAfterDate));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2021, 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
@ -39,9 +39,12 @@ import java.security.spec.InvalidParameterSpecException;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.NamedParameterSpec;
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;
@ -51,7 +54,6 @@ import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@ -686,41 +688,30 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
* 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)) {
try {
zdt = ZonedDateTime
.of(year, month, day, 0, 0, 0, 0, ZoneId.of("GMT"));
denyAfterDate = zdt.toInstant();
} catch (DateTimeException dte) {
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)) {
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());
}
}
@ -735,23 +726,22 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
@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);
}
@ -770,7 +760,7 @@ public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
debug.println("DenyAfterConstraints.permits(): " + algorithm);
}
return denyAfterDate.after(new Date());
return denyAfterDate.isAfter(Instant.now());
}
}

View File

@ -0,0 +1,43 @@
/*
* 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;
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 = is.readAllBytes();
return defineClass(name, buf, 0, buf.length);
} catch (IOException e) {
throw new ClassNotFoundException(e.getMessage());
}
}
}

View File

@ -0,0 +1,94 @@
/*
* 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 /test/lib
* @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.test.lib.SecurityTools;
import jdk.test.lib.compiler.InMemoryJavaCompiler;
import jdk.test.lib.helpers.ClassFileInstaller;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.JarUtils;
public class SignedJarWithCustomClassLoader {
public static void main(String[] args) throws Exception {
// compile the Main program
String main = """
public class Main {
public static void main(String[] args) {}
}
""";
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);
}
}