mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-30 13:08:24 +00:00
8159393: jlink should print a warning that a signed modular JAR will be treated as unsigned
Reviewed-by: alanb, sundar, mullan, weijun
This commit is contained in:
parent
2a0b3e1f75
commit
d96b3cd0cb
@ -359,9 +359,9 @@ class JImageTask {
|
||||
if (name.endsWith(".class") && !name.endsWith("module-info.class")) {
|
||||
try {
|
||||
byte[] bytes = reader.getResource(location);
|
||||
ClassReader cr =new ClassReader(bytes);
|
||||
ClassReader cr = new ClassReader(bytes);
|
||||
ClassNode cn = new ClassNode();
|
||||
cr.accept(cn, ClassReader.EXPAND_FRAMES);
|
||||
cr.accept(cn, 0);
|
||||
} catch (Exception ex) {
|
||||
log.println("Error(s) in Class: " + name);
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@ import java.lang.module.ModuleFinder;
|
||||
import java.lang.module.ModuleReference;
|
||||
import java.lang.module.ResolutionException;
|
||||
import java.lang.module.ResolvedModule;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.file.Files;
|
||||
@ -41,6 +40,7 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.tools.jlink.internal.TaskHelper.BadArgs;
|
||||
import static jdk.tools.jlink.internal.TaskHelper.JLINK_BUNDLE;
|
||||
@ -62,20 +62,8 @@ import jdk.internal.misc.SharedSecrets;
|
||||
public class JlinkTask {
|
||||
static final boolean DEBUG = Boolean.getBoolean("jlink.debug");
|
||||
|
||||
private static <T extends Throwable> void fail(Class<T> type,
|
||||
String format,
|
||||
Object... args) throws T {
|
||||
String msg = new Formatter().format(format, args).toString();
|
||||
try {
|
||||
T t = type.getConstructor(String.class).newInstance(msg);
|
||||
throw t;
|
||||
} catch (InstantiationException |
|
||||
InvocationTargetException |
|
||||
NoSuchMethodException |
|
||||
IllegalAccessException e) {
|
||||
throw new InternalError("Unable to create an instance of " + type, e);
|
||||
}
|
||||
}
|
||||
// jlink API ignores by default. Remove when signing is implemented.
|
||||
static final boolean IGNORE_SIGNING_DEFAULT = true;
|
||||
|
||||
private static final TaskHelper taskHelper
|
||||
= new TaskHelper(JLINK_BUNDLE);
|
||||
@ -143,7 +131,10 @@ public class JlinkTask {
|
||||
}, "--save-opts"),
|
||||
new Option<JlinkTask>(false, (task, opt, arg) -> {
|
||||
task.options.fullVersion = true;
|
||||
}, true, "--full-version"),};
|
||||
}, true, "--full-version"),
|
||||
new Option<JlinkTask>(false, (task, opt, arg) -> {
|
||||
task.options.ignoreSigning = true;
|
||||
}, true, "--ignore-signing-information"),};
|
||||
|
||||
private static final String PROGNAME = "jlink";
|
||||
private final OptionsValues options = new OptionsValues();
|
||||
@ -160,7 +151,8 @@ public class JlinkTask {
|
||||
/**
|
||||
* Result codes.
|
||||
*/
|
||||
static final int EXIT_OK = 0, // Completed with no errors.
|
||||
static final int
|
||||
EXIT_OK = 0, // Completed with no errors.
|
||||
EXIT_ERROR = 1, // Completed but reported errors.
|
||||
EXIT_CMDERR = 2, // Bad command-line arguments
|
||||
EXIT_SYSERR = 3, // System error or resource exhaustion.
|
||||
@ -171,12 +163,13 @@ public class JlinkTask {
|
||||
String saveoptsfile;
|
||||
boolean version;
|
||||
boolean fullVersion;
|
||||
List<Path> modulePath = new ArrayList<>();
|
||||
Set<String> limitMods = new HashSet<>();
|
||||
Set<String> addMods = new HashSet<>();
|
||||
final List<Path> modulePath = new ArrayList<>();
|
||||
final Set<String> limitMods = new HashSet<>();
|
||||
final Set<String> addMods = new HashSet<>();
|
||||
Path output;
|
||||
Path packagedModulesPath;
|
||||
ByteOrder endian = ByteOrder.nativeOrder();
|
||||
boolean ignoreSigning = false;
|
||||
}
|
||||
|
||||
int run(String[] args) {
|
||||
@ -199,7 +192,7 @@ public class JlinkTask {
|
||||
return EXIT_OK;
|
||||
}
|
||||
if (taskHelper.getExistingImage() == null) {
|
||||
if (options.modulePath == null || options.modulePath.isEmpty()) {
|
||||
if (options.modulePath.isEmpty()) {
|
||||
throw taskHelper.newBadArgs("err.modulepath.must.be.specified").showUsage(true);
|
||||
}
|
||||
createImage();
|
||||
@ -248,20 +241,25 @@ public class JlinkTask {
|
||||
plugins = plugins == null ? new PluginsConfiguration() : plugins;
|
||||
|
||||
if (config.getModulepaths().isEmpty()) {
|
||||
throw new Exception("Empty module paths");
|
||||
throw new IllegalArgumentException("Empty module paths");
|
||||
}
|
||||
|
||||
ModuleFinder finder = newModuleFinder(config.getModulepaths(),
|
||||
config.getLimitmods(),
|
||||
config.getModules());
|
||||
|
||||
if (config.getModules().isEmpty()) {
|
||||
throw new IllegalArgumentException("No modules to add");
|
||||
}
|
||||
|
||||
// First create the image provider
|
||||
ImageProvider imageProvider
|
||||
= createImageProvider(finder,
|
||||
checkAddMods(config.getModules()),
|
||||
config.getLimitmods(),
|
||||
config.getByteOrder(),
|
||||
null);
|
||||
ImageProvider imageProvider =
|
||||
createImageProvider(finder,
|
||||
config.getModules(),
|
||||
config.getLimitmods(),
|
||||
config.getByteOrder(),
|
||||
null,
|
||||
IGNORE_SIGNING_DEFAULT);
|
||||
|
||||
// Then create the Plugin Stack
|
||||
ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
|
||||
@ -299,19 +297,17 @@ public class JlinkTask {
|
||||
}
|
||||
ModuleFinder finder
|
||||
= newModuleFinder(options.modulePath, options.limitMods, options.addMods);
|
||||
try {
|
||||
options.addMods = checkAddMods(options.addMods);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
if (options.addMods.isEmpty()) {
|
||||
throw taskHelper.newBadArgs("err.mods.must.be.specified", "--add-modules")
|
||||
.showUsage(true);
|
||||
}
|
||||
// First create the image provider
|
||||
ImageProvider imageProvider
|
||||
= createImageProvider(finder,
|
||||
ImageProvider imageProvider = createImageProvider(finder,
|
||||
options.addMods,
|
||||
options.limitMods,
|
||||
options.endian,
|
||||
options.packagedModulesPath);
|
||||
options.packagedModulesPath,
|
||||
options.ignoreSigning);
|
||||
|
||||
// Then create the Plugin Stack
|
||||
ImagePluginStack stack = ImagePluginConfiguration.
|
||||
@ -321,13 +317,6 @@ public class JlinkTask {
|
||||
stack.operate(imageProvider);
|
||||
}
|
||||
|
||||
private static Set<String> checkAddMods(Set<String> addMods) {
|
||||
if (addMods.isEmpty()) {
|
||||
throw new IllegalArgumentException("no modules to add");
|
||||
}
|
||||
return addMods;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a module finder to find the observable modules specified in
|
||||
* the --module-path and --limit-modules options
|
||||
@ -343,7 +332,7 @@ public class JlinkTask {
|
||||
return finder;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Returns a module finder of the given module path that limits
|
||||
* the observable modules to those in the transitive closure of
|
||||
* the modules specified in {@code limitMods} plus other modules
|
||||
@ -376,7 +365,8 @@ public class JlinkTask {
|
||||
Set<String> addMods,
|
||||
Set<String> limitMods,
|
||||
ByteOrder order,
|
||||
Path retainModulesPath)
|
||||
Path retainModulesPath,
|
||||
boolean ignoreSigning)
|
||||
throws IOException
|
||||
{
|
||||
if (addMods.isEmpty()) {
|
||||
@ -390,10 +380,10 @@ public class JlinkTask {
|
||||
|
||||
Map<String, Path> mods = cf.modules().stream()
|
||||
.collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
|
||||
return new ImageHelper(cf, mods, order, retainModulesPath);
|
||||
return new ImageHelper(cf, mods, order, retainModulesPath, ignoreSigning);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Returns a ModuleFinder that limits observability to the given root
|
||||
* modules, their transitive dependences, plus a set of other modules.
|
||||
*/
|
||||
@ -477,36 +467,57 @@ public class JlinkTask {
|
||||
}
|
||||
|
||||
private static class ImageHelper implements ImageProvider {
|
||||
|
||||
final Set<Archive> archives;
|
||||
final ByteOrder order;
|
||||
final Path packagedModulesPath;
|
||||
final boolean ignoreSigning;
|
||||
final Set<Archive> archives;
|
||||
|
||||
ImageHelper(Configuration cf,
|
||||
Map<String, Path> modsPaths,
|
||||
ByteOrder order,
|
||||
Path packagedModulesPath) throws IOException {
|
||||
archives = modsPaths.entrySet().stream()
|
||||
.map(e -> newArchive(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toSet());
|
||||
Path packagedModulesPath,
|
||||
boolean ignoreSigning) throws IOException {
|
||||
this.order = order;
|
||||
this.packagedModulesPath = packagedModulesPath;
|
||||
this.ignoreSigning = ignoreSigning;
|
||||
this.archives = modsPaths.entrySet().stream()
|
||||
.map(e -> newArchive(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Archive newArchive(String module, Path path) {
|
||||
if (path.toString().endsWith(".jmod")) {
|
||||
return new JmodArchive(module, path);
|
||||
} else if (path.toString().endsWith(".jar")) {
|
||||
return new ModularJarArchive(module, path);
|
||||
ModularJarArchive modularJarArchive = new ModularJarArchive(module, path);
|
||||
|
||||
Stream<Archive.Entry> signatures = modularJarArchive.entries().filter((entry) -> {
|
||||
String name = entry.name().toUpperCase(Locale.ENGLISH);
|
||||
|
||||
return name.startsWith("META-INF/") && name.indexOf('/', 9) == -1 && (
|
||||
name.endsWith(".SF") ||
|
||||
name.endsWith(".DSA") ||
|
||||
name.endsWith(".RSA") ||
|
||||
name.endsWith(".EC") ||
|
||||
name.startsWith("META-INF/SIG-")
|
||||
);
|
||||
});
|
||||
|
||||
if (signatures.count() != 0) {
|
||||
if (ignoreSigning) {
|
||||
System.err.println(taskHelper.getMessage("warn.signing", path));
|
||||
} else {
|
||||
throw new IllegalArgumentException(taskHelper.getMessage("err.signing", path));
|
||||
}
|
||||
}
|
||||
|
||||
return modularJarArchive;
|
||||
} else if (Files.isDirectory(path)) {
|
||||
return new DirArchive(path);
|
||||
} else {
|
||||
fail(RuntimeException.class,
|
||||
"Selected module %s (%s) not in jmod or modular jar format",
|
||||
module,
|
||||
path);
|
||||
throw new IllegalArgumentException(
|
||||
taskHelper.getMessage("err.not.modular.format", module, path));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -212,7 +212,7 @@ public final class TaskHelper {
|
||||
mainOptions.add(new PlugOption(true, (task, opt, arg) -> {
|
||||
Path path = Paths.get(arg);
|
||||
if (!Files.exists(path) || !Files.isDirectory(path)) {
|
||||
throw newBadArgs("err.existing.image.must.exist");
|
||||
throw newBadArgs("err.image.must.exist");
|
||||
}
|
||||
existingImage = path.toAbsolutePath();
|
||||
}, true, POST_PROCESS));
|
||||
|
||||
@ -62,6 +62,9 @@ main.opt.endian=\
|
||||
main.opt.save-opts=\
|
||||
\ --save-opts <filename> Save jlink options in the given file
|
||||
|
||||
main.opt.ignore-signing-information=\
|
||||
\ --ignore-signing-information Ignore signing information in modular JARs
|
||||
|
||||
main.msg.bug=\
|
||||
An exception has occurred in jlink. \
|
||||
Please file a bug at the Java Bug Database (http://bugreport.java.com/bugreport/) \
|
||||
@ -88,7 +91,7 @@ err.modulepath.must.be.specified:--module-path must be specified
|
||||
err.mods.must.be.specified:no modules specified to {0}
|
||||
err.path.not.found=path not found: {0}
|
||||
err.path.not.valid=invalid path: {0}
|
||||
err.existing.image.must.exist=existing image doesn't exists or is not a directory
|
||||
err.image.must.exist=image does not exist or is not a directory
|
||||
err.existing.image.invalid=existing image is not valid
|
||||
err.file.not.found=cannot find file: {0}
|
||||
err.file.error=cannot access file: {0}
|
||||
@ -104,5 +107,9 @@ err.option.unsupported={0} not supported: {1}
|
||||
err.config.defaults=property {0} is missing from configuration
|
||||
err.config.defaults.value=wrong value in defaults property: {0}
|
||||
err.bom.generation=bom file generation failed: {0}
|
||||
warn.invalid.arg=Invalid classname or pathname not exist: {0}
|
||||
err.not.modular.format=selected module {0} ({1}) not in jmod or modular JAR format
|
||||
err.signing=signed modular JAR {0} is currently not supported,\
|
||||
\ use --ignore-signing-information to suppress error
|
||||
warn.signing=signed modular JAR {0} is currently not supported
|
||||
warn.invalid.arg=invalid classname or pathname not exist: {0}
|
||||
warn.split.package=package {0} defined in {1} {2}
|
||||
|
||||
195
jdk/test/tools/jlink/JLinkSigningTest.java
Normal file
195
jdk/test/tools/jlink/JLinkSigningTest.java
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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 8159393
|
||||
* @summary Test signed jars involved in image creation
|
||||
* @modules java.base/jdk.internal.jimage
|
||||
* jdk.jlink/jdk.tools.jlink.internal
|
||||
* jdk.compiler/com.sun.tools.javac
|
||||
* java.base/sun.security.tools.keytool
|
||||
* jdk.jartool/sun.security.tools.jarsigner
|
||||
* jdk.jartool/sun.tools.jar
|
||||
* @run main/othervm JLinkSigningTest
|
||||
*/
|
||||
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JLinkSigningTest {
|
||||
static final String[] MODULE_INFO = {
|
||||
"module test {",
|
||||
"}",
|
||||
};
|
||||
|
||||
static final String[] TEST_CLASS = {
|
||||
"package test;",
|
||||
"public class test {",
|
||||
" public static void main(String[] args) {",
|
||||
" }",
|
||||
"}",
|
||||
};
|
||||
|
||||
static void report(String command, String[] args) {
|
||||
System.out.println(command + " " + String.join(" ", Arrays.asList(args)));
|
||||
}
|
||||
|
||||
static void javac(String[] args) {
|
||||
report("javac", args);
|
||||
com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();
|
||||
|
||||
if (javac.compile(args) != 0) {
|
||||
throw new RuntimeException("javac failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void jar(String[] args) {
|
||||
report("jar", args);
|
||||
sun.tools.jar.Main jar = new sun.tools.jar.Main(System.out, System.err, "jar");
|
||||
|
||||
if (!jar.run(args)) {
|
||||
throw new RuntimeException("jar failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void keytool(String[] args) {
|
||||
report("keytool", args);
|
||||
|
||||
try {
|
||||
sun.security.tools.keytool.Main.main(args);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("keytool failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void jarsigner(String[] args) {
|
||||
report("jarsigner", args);
|
||||
|
||||
try {
|
||||
sun.security.tools.jarsigner.Main.main(args);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("jarsigner failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void jlink(String[] args) {
|
||||
report("jlink", args);
|
||||
|
||||
try {
|
||||
jdk.tools.jlink.internal.Main.run(new PrintWriter(System.out, true),
|
||||
new PrintWriter(System.err, true),
|
||||
args);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("jlink failed");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
final String JAVA_HOME = System.getProperty("java.home");
|
||||
Path moduleInfoJavaPath = Paths.get("module-info.java");
|
||||
Path moduleInfoClassPath = Paths.get("module-info.class");
|
||||
Path testDirectoryPath = Paths.get("test");
|
||||
Path testJavaPath = testDirectoryPath.resolve("test.java");
|
||||
Path testClassPath = testDirectoryPath.resolve("test.class");
|
||||
Path testModsDirectoryPath = Paths.get("testmods");
|
||||
Path jmodsPath = Paths.get(JAVA_HOME, "jmods");
|
||||
Path testjarPath = testModsDirectoryPath.resolve("test.jar");
|
||||
String modulesPath = testjarPath.toString() +
|
||||
File.pathSeparator +
|
||||
jmodsPath.toString();
|
||||
|
||||
try {
|
||||
Files.write(moduleInfoJavaPath, Arrays.asList(MODULE_INFO));
|
||||
Files.createDirectories(testDirectoryPath);
|
||||
Files.write(testJavaPath, Arrays.asList(TEST_CLASS));
|
||||
Files.createDirectories(testModsDirectoryPath);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("file construction failed");
|
||||
}
|
||||
|
||||
javac(new String[] {
|
||||
testJavaPath.toString(),
|
||||
moduleInfoJavaPath.toString(),
|
||||
});
|
||||
|
||||
jar(new String[] {
|
||||
"-c",
|
||||
"-f", testjarPath.toString(),
|
||||
"--module-path", jmodsPath.toString(),
|
||||
testClassPath.toString(),
|
||||
moduleInfoClassPath.toString(),
|
||||
});
|
||||
|
||||
keytool(new String[] {
|
||||
"-genkey",
|
||||
"-keyalg", "RSA",
|
||||
"-dname", "CN=John Doe, OU=JPG, O=Oracle, L=Santa Clara, ST=California, C=US",
|
||||
"-alias", "examplekey",
|
||||
"-storepass", "password",
|
||||
"-keypass", "password",
|
||||
"-keystore", "examplekeystore",
|
||||
"-validity", "365",
|
||||
});
|
||||
|
||||
jarsigner(new String[] {
|
||||
"-keystore", "examplekeystore",
|
||||
"-verbose", testjarPath.toString(),
|
||||
"-storepass", "password",
|
||||
"-keypass", "password",
|
||||
"examplekey",
|
||||
});
|
||||
|
||||
try {
|
||||
jlink(new String[] {
|
||||
"--module-path", modulesPath,
|
||||
"--add-modules", "test",
|
||||
"--output", "foo",
|
||||
});
|
||||
} catch (Throwable ex) {
|
||||
System.out.println("Failed as should");
|
||||
}
|
||||
|
||||
try {
|
||||
jlink(new String[] {
|
||||
"--module-path", modulesPath,
|
||||
"--add-modules", "test",
|
||||
"--ignore-signing-information",
|
||||
"--output", "foo",
|
||||
});
|
||||
System.out.println("Suceeded as should");
|
||||
} catch (Throwable ex) {
|
||||
System.err.println("Should not have failed");
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
System.out.println("Done");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user