Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,8 @@
package jdk.jpackage.internal;

import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE;
import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE;
import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE;

import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Map;
import java.util.Optional;
import jdk.jpackage.internal.model.ConfigException;

public abstract class MacBaseInstallerBundler extends AbstractBundler {
Expand All @@ -44,26 +38,7 @@ public MacBaseInstallerBundler() {

protected void validateAppImageAndBundeler(
Map<String, ? super Object> params) throws ConfigException {
if (PREDEFINED_APP_IMAGE.fetchFrom(params) != null) {
Path applicationImage = PREDEFINED_APP_IMAGE.fetchFrom(params);
if (new MacAppImageFileExtras(PREDEFINED_APP_IMAGE_FILE.fetchFrom(params)).signed()) {
var appLayout = ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT.resolveAt(applicationImage);
if (!Files.exists(
PackageFile.getPathInAppImage(appLayout))) {
Log.info(MessageFormat.format(I18N.getString(
"warning.per.user.app.image.signed"),
PackageFile.getPathInAppImage(appLayout)));
}
} else {
if (Optional.ofNullable(
SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
// if signing bundle with app-image, warn user if app-image
// is not already signed.
Log.info(MessageFormat.format(I18N.getString(
"warning.unsigned.app.image"), getID()));
}
}
} else {
if (PREDEFINED_APP_IMAGE.fetchFrom(params) == null) {
appImageBundler.validate(params);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
*/
package jdk.jpackage.internal;

import static jdk.jpackage.internal.MacPackagingPipeline.APPLICATION_LAYOUT;
import static jdk.jpackage.internal.MacPackagingPipeline.LayoutUtils.packagerLayout;

import java.nio.file.Files;
import java.util.Objects;
import jdk.jpackage.internal.model.ConfigException;
import jdk.jpackage.internal.model.MacApplication;
Expand Down Expand Up @@ -57,7 +59,21 @@ MacPackage create() throws ConfigException {
.installedPackageLayout(pkg.installedPackageLayout());

pkg = pkgBuilder.create();
return MacPackage.create(pkg, new MacPackageMixin.Stub(pkg.predefinedAppImage().map(v -> predefinedAppImageSigned)));

var macPkg = MacPackage.create(pkg, new MacPackageMixin.Stub(pkg.predefinedAppImage().map(v -> predefinedAppImageSigned)));
validatePredefinedAppImage(macPkg);
return macPkg;
}

private static void validatePredefinedAppImage(MacPackage pkg) {
if (pkg.predefinedAppImageSigned().orElse(false)) {
pkg.predefinedAppImage().ifPresent(predefinedAppImage -> {
var thePackageFile = PackageFile.getPathInAppImage(APPLICATION_LAYOUT);
if (!Files.exists(predefinedAppImage.resolve(thePackageFile))) {
Log.info(I18N.format("warning.per.user.app.image.signed", thePackageFile));
}
});
}
}

private final PackageBuilder pkgBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ MacPkgPackageBuilder signingBuilder(SigningIdentityBuilder v) {
}

MacPkgPackage create() throws ConfigException {
return MacPkgPackage.create(pkgBuilder.create(), new MacPkgPackageMixin.Stub(createSigningConfig()));
var pkg = MacPkgPackage.create(pkgBuilder.create(), new MacPkgPackageMixin.Stub(createSigningConfig()));
validatePredefinedAppImage(pkg);
return pkg;
}

private Optional<PkgSigningConfig> createSigningConfig() throws ConfigException {
Expand All @@ -56,6 +58,14 @@ private Optional<PkgSigningConfig> createSigningConfig() throws ConfigException
}
}

private static void validatePredefinedAppImage(MacPkgPackage pkg) {
if (!pkg.predefinedAppImageSigned().orElse(false) && pkg.sign()) {
pkg.predefinedAppImage().ifPresent(predefinedAppImage -> {
Log.info(I18N.format("warning.unsigned.app.image", "pkg"));
});
}
}

private final MacPackageBuilder pkgBuilder;
private SigningIdentityBuilder signingBuilder;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1130,6 +1130,11 @@ public static enum AppLayoutAssert {
MacHelper.verifyBundleStructure(cmd);
}
}),
MAC_BUNDLE_UNSIGNED_SIGNATURE(cmd -> {
if (TKit.isOSX() && !MacHelper.appImageSigned(cmd)) {
MacHelper.verifyUnsignedBundleSignature(cmd);
}
}),
;

AppLayoutAssert(Consumer<JPackageCommand> action) {
Expand Down
140 changes: 136 additions & 4 deletions test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.regex.Pattern;
Expand All @@ -66,6 +67,7 @@
import jdk.jpackage.internal.util.XmlUtils;
import jdk.jpackage.internal.util.function.ThrowingConsumer;
import jdk.jpackage.internal.util.function.ThrowingSupplier;
import jdk.jpackage.test.MacSign.CertificateRequest;
import jdk.jpackage.test.PackageTest.PackageHandlers;

public final class MacHelper {
Expand Down Expand Up @@ -229,25 +231,61 @@ private static void collectPListProperty(Map<String, String> accumulator, String
}
}

/**
* Returns {@code true} if the given jpackage command line is configured to sign
* predefined app image in place.
* <p>
* jpackage will not create a new app image or a native bundle.
*
* @param cmd the jpackage command to examine
* @return {@code true} if the given jpackage command line is configured to sign
* predefined app image in place and {@code false} otherwise.
*/
public static boolean signPredefinedAppImage(JPackageCommand cmd) {
Objects.requireNonNull(cmd);
if (!TKit.isOSX()) {
throw new UnsupportedOperationException();
}
return cmd.hasArgument("--mac-sign") && cmd.hasArgument("--app-image");
}

return cmd.hasArgument("--mac-sign") && cmd.hasArgument("--app-image") && cmd.isImagePackageType();
}

/**
* Returns {@code true} if the given jpackage command line is configured such
* that the app image it will produce will be signed.
* <p>
* If the jpackage command line is bundling a native package, the function
* returns {@code true} if the bundled app image will be signed.
*
* @param cmd the jpackage command to examine
* @return {@code true} if the given jpackage command line is configured such
* that the app image it will produce will be signed and {@code false}
* otherwise.
*/
public static boolean appImageSigned(JPackageCommand cmd) {
Objects.requireNonNull(cmd);
if (!TKit.isOSX()) {
throw new UnsupportedOperationException();
}

if (Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of).map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) {
var runtimeImage = Optional.ofNullable(cmd.getArgumentValue("--runtime-image")).map(Path::of);
var appImage = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of);

if (cmd.isRuntime() && Files.isDirectory(runtimeImage.orElseThrow().resolve("Contents/_CodeSignature"))) {
// If the predefined runtime is a signed bundle, bundled image should be signed too.
return true;
} else if (appImage.map(AppImageFile::load).map(AppImageFile::macSigned).orElse(false)) {
// The external app image is signed, so the app image is signed too.
return true;
}

if (!cmd.isImagePackageType() && appImage.isPresent()) {
// Building a ".pkg" or a ".dmg" bundle from the predefined app image.
// The predefined app image is unsigned, so the app image bundled
// in the output native package will be unsigned too
// (even if the ".pkg" file may be signed itself, and we never sign ".dmg" files).
return false;
}

if (!cmd.hasArgument("--mac-sign")) {
return false;
}
Expand Down Expand Up @@ -332,6 +370,100 @@ public static void writeFaPListFragment(JPackageCommand cmd, XMLStreamWriter xml
}).run();
}

public static JPackageCommand useKeychain(JPackageCommand cmd, MacSign.ResolvedKeychain keychain) {
return useKeychain(cmd, keychain.spec().keychain());
}

public static JPackageCommand useKeychain(JPackageCommand cmd, MacSign.Keychain keychain) {
return sign(cmd).addArguments("--mac-signing-keychain", keychain.name());
}

public static JPackageCommand sign(JPackageCommand cmd) {
if (!cmd.hasArgument("--mac-sign")) {
cmd.addArgument("--mac-sign");
}
return cmd;
}

public record SignKeyOption(Type type, CertificateRequest certRequest) {

public SignKeyOption {
Objects.requireNonNull(type);
Objects.requireNonNull(certRequest);
}

public enum Type {
SIGN_KEY_USER_NAME,
SIGN_KEY_IDENTITY,
;
}

@Override
public String toString() {
var sb = new StringBuffer();
applyTo((optionName, _) -> {
sb.append(String.format("{%s: %s}", optionName, certRequest));
});
return sb.toString();
}

public JPackageCommand addTo(JPackageCommand cmd) {
applyTo(cmd::addArguments);
return sign(cmd);
}

public JPackageCommand setTo(JPackageCommand cmd) {
applyTo(cmd::setArgumentValue);
return sign(cmd);
}

private void applyTo(BiConsumer<String, String> sink) {
switch (certRequest.type()) {
case INSTALLER -> {
switch (type) {
case SIGN_KEY_IDENTITY -> {
sink.accept("--mac-installer-sign-identity", certRequest.name());
return;
}
case SIGN_KEY_USER_NAME -> {
sink.accept("--mac-signing-key-user-name", certRequest.shortName());
return;
}
}
}
case CODE_SIGN -> {
switch (type) {
case SIGN_KEY_IDENTITY -> {
sink.accept("--mac-app-image-sign-identity", certRequest.name());
return;
}
case SIGN_KEY_USER_NAME -> {
sink.accept("--mac-signing-key-user-name", certRequest.shortName());
return;
}
}
}
}

throw new AssertionError();
}
}

static void verifyUnsignedBundleSignature(JPackageCommand cmd) {
if (!cmd.isImagePackageType()) {
MacSignVerify.assertUnsigned(cmd.outputBundle());
}

final Path bundleRoot;
if (cmd.isImagePackageType()) {
bundleRoot = cmd.outputBundle();
} else {
bundleRoot = cmd.pathToUnpackedPackageFile(cmd.appInstallationDirectory());
}

MacSignVerify.assertAdhocSigned(bundleRoot);
}

static PackageHandlers createDmgPackageHandlers() {
return new PackageHandlers(MacHelper::installDmg, MacHelper::uninstallDmg, MacHelper::unpackDmg);
}
Expand Down
Loading