From f1dfdc1a79f3a16eae58d15d1945541a08f7e145 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Tue, 24 Oct 2023 21:41:20 +0000 Subject: [PATCH] 8311877: [macos] Add CLI options to provide signing identity directly to codesign and productbuild Reviewed-by: asemenyuk --- .../jdk/jpackage/internal/MacAppBundler.java | 26 +++- .../jpackage/internal/MacAppImageBuilder.java | 50 ++++++-- .../internal/MacBaseInstallerBundler.java | 7 ++ .../jdk/jpackage/internal/MacPkgBundler.java | 54 ++++++-- .../resources/MacResources.properties | 3 +- .../resources/MacResources_de.properties | 3 +- .../resources/MacResources_ja.properties | 3 +- .../resources/MacResources_zh_CN.properties | 3 +- .../jdk/jpackage/internal/Arguments.java | 24 ++++ .../jpackage/internal/BundlerParamInfo.java | 28 +++-- .../jdk/jpackage/internal/ValidOptions.java | 6 +- .../resources/HelpResources.properties | 16 ++- .../resources/MainResources.properties | 5 +- .../resources/MainResources_de.properties | 3 +- .../resources/MainResources_ja.properties | 3 +- .../resources/MainResources_zh_CN.properties | 3 +- .../jpackage/macosx/SigningAppImageTest.java | 26 ++-- .../macosx/SigningAppImageTwoStepsTest.java | 34 ++++-- .../jpackage/macosx/SigningOptionsTest.java | 115 ++++++++++++++++++ ...SigningPackageFromTwoStepAppImageTest.java | 53 ++++++-- .../jpackage/macosx/SigningPackageTest.java | 86 +++++++++++-- .../macosx/SigningPackageTwoStepTest.java | 51 ++++++-- .../jpackage/macosx/base/SigningBase.java | 32 +++-- .../tests/PredefinedAppImageErrorTest.java | 2 +- 24 files changed, 531 insertions(+), 105 deletions(-) create mode 100644 test/jdk/tools/jpackage/macosx/SigningOptionsTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index cf031cb47a5..06796db9884 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -85,6 +85,13 @@ public class MacAppBundler extends AppImageBundler { }, (s, p) -> s); + public static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = + new StandardBundlerParam<>( + Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), + String.class, + params -> "", + null); + public static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = new StandardBundlerParam<>( Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), @@ -127,14 +134,21 @@ public class MacAppBundler extends AppImageBundler { // reject explicitly set sign to true and no valid signature key if (Optional.ofNullable( SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { - String signingIdentity = - DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); - if (signingIdentity == null) { - throw new ConfigException( - I18N.getString("error.explicit-sign-no-cert"), - I18N.getString("error.explicit-sign-no-cert.advice")); + // Validate DEVELOPER_ID_APP_SIGNING_KEY only if user provided + // SIGNING_KEY_USER. + if (!SIGNING_KEY_USER.getIsDefaultValue(params)) { // --mac-signing-key-user-name + String signingIdentity = + DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); + if (signingIdentity == null) { + throw new ConfigException( + I18N.getString("error.explicit-sign-no-cert"), + I18N.getString("error.explicit-sign-no-cert.advice")); + } } + // No need to validate --mac-app-image-sign-identity, since it is + // pass through option. + // Signing will not work without Xcode with command line developer tools try { ProcessBuilder pb = new ProcessBuilder("/usr/bin/xcrun", "--help"); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index d9250ae1474..ea86c41d981 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -25,8 +25,10 @@ package jdk.jpackage.internal; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.PrintStream; import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; @@ -53,7 +55,10 @@ import jdk.internal.util.OperatingSystem; import jdk.internal.util.OSVersion; import static jdk.jpackage.internal.MacAppBundler.BUNDLE_ID_SIGNING_PREFIX; import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY; +import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; +import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; +import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; @@ -395,12 +400,25 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { } catch (InterruptedException e) { Log.error(e.getMessage()); } - String signingIdentity = - DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); + String signingIdentity = null; + // Try --mac-app-image-sign-identity first if set + if (!APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) { + signingIdentity = APP_IMAGE_SIGN_IDENTITY.fetchFrom(params); + } else { + // Check if INSTALLER_SIGN_IDENTITY is set and if it is set + // then do not sign app image, otherwise use --mac-signing-key-user-name + if (INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) { + // --mac-sign and/or --mac-signing-key-user-name case + signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); + } + } if (signingIdentity != null) { signAppBundle(params, root, signingIdentity, BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), ENTITLEMENTS.fetchFrom(params)); + } else { + // Case when user requested to sign installer only + signAppBundle(params, root, "-", null, null); } restoreKeychainList(params); } else if (OperatingSystem.isMacOS()) { @@ -715,6 +733,25 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { return args; } + private static void runCodesign(ProcessBuilder pb, boolean quiet) + throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos)) { + try { + IOUtils.exec(pb, false, ps, false, + Executor.INFINITE_TIMEOUT, quiet); + } catch (IOException ioe) { + // Log output of "codesign" in case of + // error. It should help user to diagnose + // issue when using --mac-app-image-sign-identity + Log.info(MessageFormat.format(I18N.getString( + "error.tool.failed.with.output"), "codesign")); + Log.info(baos.toString().strip()); + throw ioe; + } + } + } + static void signAppBundle( Map params, Path appLocation, String signingIdentity, String identifierPrefix, Path entitlements) @@ -781,8 +818,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { p.toFile().setWritable(true, true); ProcessBuilder pb = new ProcessBuilder(args); // run quietly - IOUtils.exec(pb, false, null, false, - Executor.INFINITE_TIMEOUT, true); + runCodesign(pb, true); Files.setPosixFilePermissions(p, oldPermissions); } catch (IOException ioe) { toThrow.set(ioe); @@ -810,8 +846,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { List args = getCodesignArgs(true, path, signingIdentity, identifierPrefix, entitlements, keyChain); ProcessBuilder pb = new ProcessBuilder(args); - - IOUtils.exec(pb); + runCodesign(pb, false); } catch (IOException e) { toThrow.set(e); } @@ -842,8 +877,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { List args = getCodesignArgs(true, appLocation, signingIdentity, identifierPrefix, entitlements, keyChain); ProcessBuilder pb = new ProcessBuilder(args); - - IOUtils.exec(pb); + runCodesign(pb, false); } private static String extractBundleIdentifier(Map params) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index b4f63d66f57..8d9db0a0077 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -79,6 +79,13 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { params -> "", null); + public static final BundlerParamInfo INSTALLER_SIGN_IDENTITY = + new StandardBundlerParam<>( + Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), + String.class, + params -> "", + null); + public static final BundlerParamInfo MAC_INSTALLER_NAME = new StandardBundlerParam<> ( "mac.installerName", diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 60cd11b6f06..6ac84975451 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -28,7 +28,9 @@ package jdk.jpackage.internal; import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; @@ -54,6 +56,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; +import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; +import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.OverridableResource.createResource; @@ -605,8 +609,19 @@ public class MacPkgBundler extends MacBaseInstallerBundler { Log.verbose(I18N.getString("message.signing.pkg")); } - String signingIdentity = - DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); + String signingIdentity = null; + // --mac-installer-sign-identity + if (!INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) { + signingIdentity = INSTALLER_SIGN_IDENTITY.fetchFrom(params); + } else { + // Use --mac-signing-key-user-name if user did not request + // to sign just app image using --mac-app-image-sign-identity + if (APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) { + // --mac-signing-key-user-name + signingIdentity = DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); + } + } + if (signingIdentity != null) { commandLine.add("--sign"); commandLine.add(signingIdentity); @@ -638,7 +653,21 @@ public class MacPkgBundler extends MacBaseInstallerBundler { commandLine.add(finalPKG.toAbsolutePath().toString()); pb = new ProcessBuilder(commandLine); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos)) { + try { + IOUtils.exec(pb, false, ps, true, Executor.INFINITE_TIMEOUT); + } catch (IOException ioe) { + // Log output of "productbuild" in case of + // error. It should help user to diagnose + // issue when using --mac-installer-sign-identity + Log.info(MessageFormat.format(I18N.getString( + "error.tool.failed.with.output"), "productbuild")); + Log.info(baos.toString().strip()); + throw ioe; + } + } return finalPKG; } catch (Exception ignored) { @@ -702,14 +731,19 @@ public class MacPkgBundler extends MacBaseInstallerBundler { // reject explicitly set sign to true and no valid signature key if (Optional.ofNullable( SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { - String signingIdentity = - DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); - if (signingIdentity == null) { - throw new ConfigException( - I18N.getString("error.explicit-sign-no-cert"), - I18N.getString( - "error.explicit-sign-no-cert.advice")); + if (!SIGNING_KEY_USER.getIsDefaultValue(params)) { + String signingIdentity = + DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); + if (signingIdentity == null) { + throw new ConfigException( + I18N.getString("error.explicit-sign-no-cert"), + I18N.getString( + "error.explicit-sign-no-cert.advice")); + } } + + // No need to validate --mac-installer-sign-identity, since it is + // pass through option. } // hdiutil is always available so there's no need diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index c575df2494e..de4e7157b2a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Install Xcode with command line developer tools. error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one error.app-image.mac-sign.required=Error: --mac-sign option is required with predefined application image and with type [app-image] +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=Bundle config file resource.app-info-plist=Application Info.plist resource.runtime-info-plist=Java Runtime Info.plist diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 6dd037c9bce..8586041d417 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Installieren Sie Xcode mit Befehlszeilen-Entwickle error.cert.not.found=Kein Zertifikat gefunden, das [{0}] mit Schlüsselbund [{1}] entspricht error.multiple.certs.found=WARNUNG: Mehrere Zertifikate gefunden, die [{0}] mit Schlüsselbund [{1}] entsprechen. Es wird das erste Zertifikat verwendet error.app-image.mac-sign.required=Fehler: Die Option "--mac-sign" ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=Bundle-Konfigurationsdatei resource.app-info-plist=Info.plist der Anwendung resource.runtime-info-plist=Info.plist von Java Runtime diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index b75d1dc465f..518e3e45f97 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Xcodeとコマンドライン・デベロッパ・ error.cert.not.found=キーチェーン[{1}]を使用する[{0}]と一致する証明書が見つかりません error.multiple.certs.found=警告: キーチェーン[{1}]を使用する[{0}]と一致する複数の証明書が見つかりました。最初のものを使用します error.app-image.mac-sign.required=エラー: --mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=バンドル構成ファイル resource.app-info-plist=アプリケーションのInfo.plist resource.runtime-info-plist=JavaランタイムのInfo.plist diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index dc1f592852d..c4e4bd22939 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=安装带命令行开发人员工具的 Xcode。 error.cert.not.found=使用密钥链 [{1}] 找不到与 [{0}] 匹配的证书 error.multiple.certs.found=警告:使用密钥链 [{1}] 找到多个与 [{0}] 匹配的证书,将使用第一个证书 error.app-image.mac-sign.required=错误:预定义的应用程序映像和类型 [app image] 需要 --mac-sign 选项 +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=包配置文件 resource.app-info-plist=应用程序 Info.plist resource.runtime-info-plist=Java 运行时 Info.plist diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index b4a28e7fb3c..16cd89d9d52 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -338,6 +338,12 @@ public class Arguments { MAC_SIGNING_KEY_NAME ("mac-signing-key-user-name", OptionCategories.PLATFORM_MAC), + MAC_APP_IMAGE_SIGN_IDENTITY ("mac-app-image-sign-identity", + OptionCategories.PLATFORM_MAC), + + MAC_INSTALLER_SIGN_IDENTITY ("mac-installer-sign-identity", + OptionCategories.PLATFORM_MAC), + MAC_SIGNING_KEYCHAIN ("mac-signing-keychain", OptionCategories.PLATFORM_MAC), @@ -631,6 +637,24 @@ public class Arguments { CLIOptions.JLINK_OPTIONS.getIdWithPrefix()); } } + if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) && + allOptions.contains(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY)) { + throw new PackagerException("ERR_MutuallyExclusiveOptions", + CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(), + CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getIdWithPrefix()); + } + if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) && + allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) { + throw new PackagerException("ERR_MutuallyExclusiveOptions", + CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(), + CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix()); + } + if (isMac && (imageOnly || "dmg".equals(type)) && + allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) { + throw new PackagerException("ERR_InvalidTypeOption", + CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix(), + type); + } if (allOptions.contains(CLIOptions.DMG_CONTENT) && !("dmg".equals(type))) { throw new PackagerException("ERR_InvalidTypeOption", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index 4173980002b..fa99073ff7f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2023, 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 @@ -46,11 +46,6 @@ class BundlerParamInfo { */ Class valueType; - /** - * Indicates if value was set using default value function - */ - boolean isDefaultValue; - /** * If the value is not set, and no fallback value is found, * the parameter uses the value returned by the producer. @@ -70,8 +65,24 @@ class BundlerParamInfo { return valueType; } - boolean getIsDefaultValue() { - return isDefaultValue; + /** + * Returns true if value was not provided on command line for this + * parameter. + * + * @param params - params from which value will be fetch + * @return true if value was not provided on command line, false otherwise + */ + boolean getIsDefaultValue(Map params) { + Object o = params.get(getID()); + if (o != null) { + return false; // We have user provided value + } + + if (params.containsKey(getID())) { + return false; // explicit nulls are allowed for provided value + } + + return true; } Function, T> getDefaultValueFunction() { @@ -114,7 +125,6 @@ class BundlerParamInfo { T result = getDefaultValueFunction().apply(params); if (result != null) { params.put(getID(), result); - isDefaultValue = true; } return result; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java index 4d3e163cdc1..89a2e4b56fe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java @@ -27,6 +27,7 @@ package jdk.jpackage.internal; import java.util.EnumSet; import java.util.HashMap; + import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.Arguments.CLIOptions; @@ -62,7 +63,6 @@ class ValidOptions { private static final HashMap> options = new HashMap<>(); - // initializing list of mandatory arguments static { put(CLIOptions.NAME.getId(), USE.ALL); @@ -130,6 +130,10 @@ class ValidOptions { EnumSet.of(USE.ALL, USE.SIGN)); put(CLIOptions.MAC_SIGNING_KEY_NAME.getId(), EnumSet.of(USE.ALL, USE.SIGN)); + put(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), + EnumSet.of(USE.ALL, USE.SIGN)); + put(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), + EnumSet.of(USE.INSTALL, USE.SIGN)); put(CLIOptions.MAC_SIGNING_KEYCHAIN.getId(), EnumSet.of(USE.ALL, USE.SIGN)); put(CLIOptions.MAC_APP_STORE.getId(), USE.ALL); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties index 6c92cf3e55c..c21daab30d0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -265,7 +265,19 @@ MSG_Help_mac_launcher=\ \ Name of the keychain to search for the signing identity\n\ \ If not specified, the standard keychains are used.\n\ \ --mac-signing-key-user-name \n\ -\ Team or user name portion of Apple signing identities.\n\ +\ Team or user name portion of Apple signing identities. For direct\n\ +\ control of the signing identity used to sign application images or\n\ +\ installers use --mac-app-image-sign-identity and/or\n\ +\ --mac-installer-sign-identity. This option cannot be combined with\n\ +\ --mac-app-image-sign-identity or --mac-installer-sign-identity.\n\ +\ --mac-app-image-sign-identity \n\ +\ Identity used to sign application image. This value will be passed\n\ +\ directly to --sign option of "codesign" tool. This option cannot\n\ +\ be combined with --mac-signing-key-user-name.\n\ +\ --mac-installer-sign-identity \n\ +\ Identity used to sign "pkg" installer. This value will be passed\n\ +\ directly to --sign option of "productbuild" tool. This option\n\ +\ cannot be combined with --mac-signing-key-user-name.\n\ \ --mac-app-store\n\ \ Indicates that the jpackage output is intended for the\n\ \ Mac App Store.\n\ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 5297ef92d34..4c5d51d5bcc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -92,10 +92,11 @@ ERR_NoMainClass=Error: Main application class is missing ERR_UnsupportedOption=Error: Option [{0}] is not valid on this platform ERR_InvalidTypeOption=Error: Option [{0}] is not valid with type [{1}] ERR_NoInstallerEntryPoint=Error: Option [{0}] is not valid without --module or --main-jar entry point option -ERR_MutuallyExclusiveOptions="Error: Mutually exclusive options [{0}] and [{1}] +ERR_MutuallyExclusiveOptions=Error: Mutually exclusive options [{0}] and [{1}] ERR_InvalidOptionWithAppImageSigning=Error: Option [{0}] is not valid when signing application image ERR_MissingArgument=Error: Missing argument: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=Error: No application jars found ERR_AppImageNotExist=Error: App image directory "{0}" does not exist ERR_NoAddLauncherName=Error: --add-launcher option requires a name and a file path (--add-launcher =) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties index 732c8a339f9..e505262ea28 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="Fehler: Optionen [{0}] und [{1}] schließen sich g ERR_InvalidOptionWithAppImageSigning=Fehler: Option [{0}] ist nicht gültig beim Signieren eines Anwendungsimages ERR_MissingArgument=Fehler: Fehlendes Argument: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=Fehler: Keine Anwendungs-JAR-Dateien gefunden ERR_AppImageNotExist=Fehler: Anwendungsimageverzeichnis "{0}" ist nicht vorhanden ERR_NoAddLauncherName=Fehler: Für Option --add-launcher müssen ein Name und ein Dateipfad angegeben werden (--add-launcher =) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties index 8b4c457e61c..6cc9c23793c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="エラー: 相互排他的なオプション[{0}] ERR_InvalidOptionWithAppImageSigning=エラー: アプリケーション・イメージへの署名時にオプション[{0}]が有効ではありません ERR_MissingArgument=エラー: 引数がありません: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=エラー: アプリケーションjarが見つかりませんでした ERR_AppImageNotExist=エラー: アプリケーション・イメージ・ディレクトリ"{0}"は存在しません ERR_NoAddLauncherName=エラー: --add-launcherオプションには名前およびファイル・パスが必要です(--add-launcher =) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties index 4a37c781ba4..7eab865568c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2017, 2023, 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 @@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="错误:选项 [{0}] 和 [{1}] 相互排斥 ERR_InvalidOptionWithAppImageSigning=错误:对应用程序映像签名时,选项 [{0}] 无效 ERR_MissingArgument=错误: 缺少参数: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=错误: 找不到应用程序 jar ERR_AppImageNotExist=错误:应用程序映像目录 "{0}" 不存在 ERR_NoAddLauncherName=错误:--add-launcher 选项需要一个名称和一个文件路径 (--add-launcher =) diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 6cea5ebd332..65793baa096 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -55,28 +55,40 @@ import jdk.jpackage.test.AdditionalLauncher; * @build SigningAppImageTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTest */ public class SigningAppImageTest { @Test - @Parameter({"true", "0"}) // ({"sign or not", "certificate index"}) - @Parameter({"true", "1"}) - @Parameter({"false", "-1"}) + // ({"sign or not", "signing-key or sign-identity", "certificate index"}) + // Sign, signing-key and ASCII certificate + @Parameter({"true", "true", SigningBase.ASCII_INDEX}) + // Sign, signing-key and UNICODE certificate + @Parameter({"true", "true", SigningBase.UNICODE_INDEX}) + // Sign, signing-indentity and UNICODE certificate + @Parameter({"true", "false", SigningBase.UNICODE_INDEX}) + // Unsigned + @Parameter({"false", "true", "-1"}) public void test(String... testArgs) throws Exception { boolean doSign = Boolean.parseBoolean(testArgs[0]); - int certIndex = Integer.parseInt(testArgs[1]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + int certIndex = Integer.parseInt(testArgs[2]); SigningCheck.checkCertificates(certIndex); JPackageCommand cmd = JPackageCommand.helloAppImage(); if (doSign) { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(certIndex), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(certIndex)); + } else { + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(certIndex)); + } } AdditionalLauncher testAL = new AdditionalLauncher("testAL"); testAL.applyTo(cmd); diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index b5d1030ab95..cf479d9ba94 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -56,15 +56,23 @@ import jdk.jpackage.test.AdditionalLauncher; * @build SigningAppImageTwoStepsTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTwoStepsTest */ public class SigningAppImageTwoStepsTest { @Test - @Parameter("true") - @Parameter("false") - public void test(boolean signAppImage) throws Exception { + // ({"sign or not", "signing-key or sign-identity"}) + // Sign and signing-key + @Parameter({"true", "true"}) + // Sign and sign-identity + @Parameter({"true", "false"}) + // Unsigned + @Parameter({"false", "true"}) + public void test(String... testArgs) throws Exception { + boolean signAppImage = Boolean.parseBoolean(testArgs[0]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); Path appimageOutput = TKit.createTempDirectory("appimage"); @@ -76,10 +84,15 @@ public class SigningAppImageTwoStepsTest { .setArgumentValue("--dest", appimageOutput); if (signAppImage) { appImageCmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + appImageCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } } // Add addtional launcher @@ -97,9 +110,14 @@ public class SigningAppImageTwoStepsTest { cmd.setPackageType(PackageType.IMAGE) .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) .addArguments("--mac-sign") - .addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)) .addArguments("--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } cmd.executeAndAssertImageCreated(); // Should be signed app image diff --git a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java new file mode 100644 index 00000000000..10b2dd6c8d2 --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2023, 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.util.Collection; +import java.util.List; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary Test jpackage signing options errors + * @library ../helpers + * @build SigningOptionsTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @requires (os.family == "mac") + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningOptionsTest + * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useExecutableByDefault + */ + +/* + * @test + * @summary Test jpackage signing options errors + * @library ../helpers + * @build SigningOptionsTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @requires (os.family == "mac") + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningOptionsTest + * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault + */ + +public final class SigningOptionsTest { + + private final String expectedError; + private final JPackageCommand cmd; + + @Parameters + public static Collection input() { + return List.of(new Object[][]{ + // --mac-signing-key-user-name and --mac-app-image-sign-identity + {"Hello", + new String[]{"--mac-sign", + "--mac-signing-key-user-name", "test-key", + "--mac-app-image-sign-identity", "test-identity"}, + null, + "Mutually exclusive options"}, + // --mac-signing-key-user-name and --mac-installer-sign-identity + {"Hello", + new String[]{"--mac-sign", + "--mac-signing-key-user-name", "test-key", + "--mac-installer-sign-identity", "test-identity"}, + null, + "Mutually exclusive options"}, + // --mac-installer-sign-identity and --type app-image + {"Hello", + new String[]{"--mac-sign", + "--mac-installer-sign-identity", "test-identity"}, + null, + "Option [--mac-installer-sign-identity] is not valid with type"}, + // --mac-installer-sign-identity and --type dmg + {"Hello", + new String[]{"--type", "dmg", + "--mac-sign", + "--mac-installer-sign-identity", "test-identity"}, + new String[]{"--type"}, + "Option [--mac-installer-sign-identity] is not valid with type"}, + }); + } + + public SigningOptionsTest(String javaAppDesc, String[] jpackageArgs, + String[] removeArgs, String expectedError) { + this.expectedError = expectedError; + + cmd = JPackageCommand.helloAppImage(javaAppDesc) + .saveConsoleOutput(true).dumpOutput(true); + if (jpackageArgs != null) { + cmd.addArguments(jpackageArgs); + } if (removeArgs != null) { + for (String arg : removeArgs) { + cmd.removeArgumentWithValue(arg); + } + } + } + + @Test + public void test() { + List output = cmd.execute(1).getOutput(); + TKit.assertNotNull(output, "output is null"); + TKit.assertTextStream(expectedError).apply(output.stream()); + } + +} diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index 861bcecfe09..48f5dca8986 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -72,7 +72,7 @@ public class SigningPackageFromTwoStepAppImageTest { } Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, SigningBase.DEFAULT_INDEX); + SigningBase.verifyPkgutil(outputBundle, true, SigningBase.DEFAULT_INDEX); SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX); } @@ -97,9 +97,17 @@ public class SigningPackageFromTwoStepAppImageTest { } @Test - @Parameter("true") - @Parameter("false") - public static void test(boolean signAppImage) throws Exception { + // ({"sign or not", "signing-key or sign-identity"}) + // Sign and signing-key + @Parameter({"true", "true"}) + // Sign and sign-identity + @Parameter({"true", "false"}) + // Unsigned + @Parameter({"false", "true"}) + public void test(String... testArgs) throws Exception { + boolean signAppImage = Boolean.parseBoolean(testArgs[0]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); Path appimageOutput = TKit.createTempDirectory("appimage"); @@ -110,9 +118,15 @@ public class SigningPackageFromTwoStepAppImageTest { JPackageCommand appImageCmd = JPackageCommand.helloAppImage() .setArgumentValue("--dest", appimageOutput); if (signAppImage) { - appImageCmd.addArguments("--mac-sign", "--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX), + appImageCmd.addArguments("--mac-sign", "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + appImageCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } } // Generate app image @@ -126,9 +140,14 @@ public class SigningPackageFromTwoStepAppImageTest { appImageSignedCmd.setPackageType(PackageType.IMAGE) .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) .addArguments("--mac-sign") - .addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)) .addArguments("--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + appImageSignedCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageSignedCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } appImageSignedCmd.executeAndAssertImageCreated(); // Should be signed app image @@ -141,16 +160,30 @@ public class SigningPackageFromTwoStepAppImageTest { cmd.removeArgumentWithValue("--input"); if (signAppImage) { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + cmd.addArguments("--mac-installer-sign-identity", + SigningBase.getInstallerCert(SigningBase.DEFAULT_INDEX)); + } } }) .forTypes(PackageType.MAC_PKG) .addBundleVerifier( SigningPackageFromTwoStepAppImageTest::verifyPKG) .forTypes(PackageType.MAC_DMG) + .addInitializer(cmd -> { + if (signAppImage && !signingKey) { + // jpackage throws expected error with + // --mac-installer-sign-identity and DMG type + cmd.removeArgument("--mac-sign"); + cmd.removeArgumentWithValue("--mac-signing-keychain"); + cmd.removeArgumentWithValue("--mac-installer-sign-identity"); + } + }) .addBundleVerifier( SigningPackageFromTwoStepAppImageTest::verifyDMG) .addBundleVerifier( diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index d7a2395db2a..c555b0386cd 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -59,15 +59,27 @@ import jdk.jpackage.test.Annotations.Parameter; * @build SigningPackageTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTest */ public class SigningPackageTest { + private static boolean isAppImageSigned(JPackageCommand cmd) { + return cmd.hasArgument("--mac-signing-key-user-name") || + cmd.hasArgument("--mac-app-image-sign-identity"); + } + + private static boolean isPKGSigned(JPackageCommand cmd) { + return cmd.hasArgument("--mac-signing-key-user-name") || + cmd.hasArgument("--mac-installer-sign-identity"); + } + private static void verifyPKG(JPackageCommand cmd) { Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, getCertIndex(cmd)); - SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); + SigningBase.verifyPkgutil(outputBundle, isPKGSigned(cmd), getCertIndex(cmd)); + if (isPKGSigned(cmd)) { + SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); + } } private static void verifyDMG(JPackageCommand cmd) { @@ -82,22 +94,45 @@ public class SigningPackageTest { // We will be called with all folders in DMG since JDK-8263155, but // we only need to verify app. if (dmgImage.endsWith(cmd.name() + ".app")) { - SigningBase.verifyCodesign(launcherPath, true, getCertIndex(cmd)); - SigningBase.verifyCodesign(dmgImage, true, getCertIndex(cmd)); - SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); + SigningBase.verifyCodesign(launcherPath, isAppImageSigned(cmd), + getCertIndex(cmd)); + SigningBase.verifyCodesign(dmgImage, isAppImageSigned(cmd), + getCertIndex(cmd)); + if (isAppImageSigned(cmd)) { + SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); + } } }); } private static int getCertIndex(JPackageCommand cmd) { - String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); - return SigningBase.getDevNameIndex(devName); + if (cmd.hasArgument("--mac-signing-key-user-name")) { + String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); + return SigningBase.getDevNameIndex(devName); + } else { + // Signing-indentity + return Integer.valueOf(SigningBase.UNICODE_INDEX); + } } @Test - @Parameter("0") - @Parameter("1") - public static void test(int certIndex) throws Exception { + // ("signing-key or sign-identity", "sign app-image", "sign pkg", "certificate index"}) + // Signing-key and ASCII certificate + @Parameter({"true", "true", "true", SigningBase.ASCII_INDEX}) + // Signing-key and UNICODE certificate + @Parameter({"true", "true", "true", SigningBase.UNICODE_INDEX}) + // Signing-indentity and UNICODE certificate + @Parameter({"false", "true", "true", SigningBase.UNICODE_INDEX}) + // Signing-indentity, but sign app-image only and UNICODE certificate + @Parameter({"false", "true", "false", SigningBase.UNICODE_INDEX}) + // Signing-indentity, but sign pkg only and UNICODE certificate + @Parameter({"false", "false", "true", SigningBase.UNICODE_INDEX}) + public static void test(String... testArgs) throws Exception { + boolean signingKey = Boolean.parseBoolean(testArgs[0]); + boolean signAppImage = Boolean.parseBoolean(testArgs[1]); + boolean signPKG = Boolean.parseBoolean(testArgs[2]); + int certIndex = Integer.parseInt(testArgs[3]); + SigningCheck.checkCertificates(certIndex); new PackageTest() @@ -105,12 +140,39 @@ public class SigningPackageTest { .forTypes(PackageType.MAC) .addInitializer(cmd -> { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", SigningBase.getDevName(certIndex), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(certIndex)); + } else { + if (signAppImage) { + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(certIndex)); + } + if (signPKG) { + cmd.addArguments("--mac-installer-sign-identity", + SigningBase.getInstallerCert(certIndex)); + } + } }) .forTypes(PackageType.MAC_PKG) .addBundleVerifier(SigningPackageTest::verifyPKG) .forTypes(PackageType.MAC_DMG) + .addInitializer(cmd -> { + if (!signingKey) { + // jpackage throws expected error with + // --mac-installer-sign-identity and DMG type + cmd.removeArgumentWithValue("--mac-installer-sign-identity"); + // In case of not signing app image and DMG we need to + // remove signing completely, otherwise we will default + // to --mac-signing-key-user-name once + // --mac-installer-sign-identity is removed. + if (!signAppImage) { + cmd.removeArgumentWithValue("--mac-signing-keychain"); + cmd.removeArgument("--mac-sign"); + } + } + }) .addBundleVerifier(SigningPackageTest::verifyDMG) .addBundleVerifier(SigningPackageTest::verifyAppImageInDMG) .run(); diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 66145a9793b..a34f7921b91 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -73,7 +73,7 @@ public class SigningPackageTwoStepTest { } Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, SigningBase.DEFAULT_INDEX); + SigningBase.verifyPkgutil(outputBundle, true, SigningBase.DEFAULT_INDEX); SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX); } @@ -101,10 +101,18 @@ public class SigningPackageTwoStepTest { } @Test - @Parameter("true") - @Parameter("false") - public static void test(boolean signAppImage) throws Exception { - SigningCheck.checkCertificates(0); + // (Signed, "signing-key or sign-identity"}) + // Signed and signing-key + @Parameter({"true", "true"}) + // Signed and signing-identity + @Parameter({"true", "false"}) + // Unsigned + @Parameter({"false", "true"}) + public static void test(String... testArgs) throws Exception { + boolean signAppImage = Boolean.parseBoolean(testArgs[0]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + + SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); Path appimageOutput = TKit.createTempDirectory("appimage"); @@ -112,10 +120,15 @@ public class SigningPackageTwoStepTest { .setArgumentValue("--dest", appimageOutput); if (signAppImage) { appImageCmd.addArguments("--mac-sign") - .addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(0)) - .addArguments("--mac-signing-keychain", - SigningBase.getKeyChain()); + .addArguments("--mac-signing-keychain", + SigningBase.getKeyChain()); + if (signingKey) { + appImageCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } } new PackageTest() @@ -126,15 +139,31 @@ public class SigningPackageTwoStepTest { cmd.removeArgumentWithValue("--input"); if (signAppImage) { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(0), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + cmd.addArguments("--mac-installer-sign-identity", + SigningBase.getInstallerCert(SigningBase.DEFAULT_INDEX)); + } } }) .forTypes(PackageType.MAC_PKG) .addBundleVerifier(SigningPackageTwoStepTest::verifyPKG) .forTypes(PackageType.MAC_DMG) + .addInitializer(cmd -> { + if (signAppImage && !signingKey) { + // jpackage throws expected error with + // --mac-installer-sign-identity and DMG type + cmd.removeArgumentWithValue("--mac-installer-sign-identity"); + // It will do nothing, but it signals test that app + // image itself is signed for verification. + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } + }) .addBundleVerifier(SigningPackageTwoStepTest::verifyDMG) .addBundleVerifier(SigningPackageTwoStepTest::verifyAppImageInDMG) .run(); diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java index 702e7b1f7ae..15031bc42be 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningBase.java @@ -33,6 +33,8 @@ import jdk.jpackage.test.Executor.Result; public class SigningBase { public static int DEFAULT_INDEX = 0; + public static final String ASCII_INDEX = "0"; + public static final String UNICODE_INDEX = "0"; private static String [] DEV_NAMES = { "jpackage.openjdk.java.net", "jpackage.openjdk.java.net (ö)", @@ -182,22 +184,30 @@ public class SigningBase { checkString(output, lookupString); } - private static List pkgutilResult(Path target) { + private static List pkgutilResult(Path target, boolean signed) { List result = new Executor() .setExecutable("/usr/sbin/pkgutil") .addArguments("--check-signature", target.toString()) - .executeAndGetOutput(); + .saveOutput() + .execute(signed ? 0 : 1) + .getOutput(); return result; } - private static void verifyPkgutilResult(List result, int certIndex) { + private static void verifyPkgutilResult(List result, boolean signed, + int certIndex) { result.stream().forEachOrdered(TKit::trace); - String lookupString = "Status: signed by"; - checkString(result, lookupString); - lookupString = "1. " + getInstallerCert(certIndex); - checkString(result, lookupString); + if (signed) { + String lookupString = "Status: signed by"; + checkString(result, lookupString); + lookupString = "1. " + getInstallerCert(certIndex); + checkString(result, lookupString); + } else { + String lookupString = "Status: no signature"; + checkString(result, lookupString); + } } public static void verifyCodesign(Path target, boolean signed, int certIndex) { @@ -228,9 +238,9 @@ public class SigningBase { verifySpctlResult(output, target, type, result.getExitCode(), certIndex); } - public static void verifyPkgutil(Path target, int certIndex) { - List result = pkgutilResult(target); - verifyPkgutilResult(result, certIndex); + public static void verifyPkgutil(Path target, boolean signed, int certIndex) { + List result = pkgutilResult(target, signed); + verifyPkgutilResult(result, signed, certIndex); } public static void verifyAppImageSignature(JPackageCommand appImageCmd, @@ -247,7 +257,7 @@ public class SigningBase { Path appImage = appImageCmd.outputBundle(); SigningBase.verifyCodesign(appImage, isSigned, SigningBase.DEFAULT_INDEX); if (isSigned) { - SigningBase.verifySpctl(appImage, "exec", 0); + SigningBase.verifySpctl(appImage, "exec", SigningBase.DEFAULT_INDEX); } } diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java index 8fb3e602449..d03c7cf28df 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java @@ -69,7 +69,7 @@ public final class PredefinedAppImageErrorTest { }, // --mac-app-store is required {"Hello", - new String[]{"--mac-sign", "--mac-app-store"}, + new String[]{"--mac-sign", "--mac-app-store", "--mac-app-image-sign-identity", "test"}, new String[]{"--input", "--dest", "--name", "--main-jar", "--main-class"}, TKit.isOSX() ? "Option [--mac-app-store] is not valid" :