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 da174a50bfd..d9250ae1474 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -715,7 +715,7 @@ public class MacAppImageBuilder extends AbstractAppImageBuilder { return args; } - private static void signAppBundle( + static void signAppBundle( Map params, Path appLocation, String signingIdentity, String identifierPrefix, Path entitlements) throws IOException { 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 5bcccc061a4..31bef8416fc 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, 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 @@ -188,6 +188,12 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { !AppImageFile.load(predefinedImage).isSigned()) { new PackageFile(APP_NAME.fetchFrom(params)).save( ApplicationLayout.macAppImage().resolveAt(appDir)); + // We need to re-sign app image after adding ".package" to it. + // We only do this if app image was not signed which means it is + // signed with ad-hoc signature. App bundles with ad-hoc + // signature are sealed, but without a signing identity, so we + // need to re-sign it after modification. + MacAppImageBuilder.signAppBundle(params, appDir, "-", null, null); } } else { appDir = appImageBundler.execute(params, appImageRoot); diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index 79c06607482..29b4ec50bc6 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -79,7 +79,7 @@ public class SigningPackageFromTwoStepAppImageTest { private static void verifyDMG(JPackageCommand cmd) { // DMG always unsigned, so we will check it Path outputBundle = cmd.outputBundle(); - SigningBase.verifyCodesign(outputBundle, false); + SigningBase.verifyDMG(outputBundle); } private static void verifyAppImageInDMG(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index f355a28b6a3..e7bb97784a5 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -71,7 +71,7 @@ public class SigningPackageTest { private static void verifyDMG(JPackageCommand cmd) { Path outputBundle = cmd.outputBundle(); - SigningBase.verifyCodesign(outputBundle, false); + SigningBase.verifyDMG(outputBundle); } private static void verifyAppImageInDMG(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 5dde721bdad..f0442f92af4 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -62,7 +62,7 @@ import jdk.jpackage.test.Annotations.Parameter; * @build SigningPackageTwoStepTest * @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=SigningPackageTwoStepTest */ public class SigningPackageTwoStepTest { @@ -80,7 +80,7 @@ public class SigningPackageTwoStepTest { private static void verifyDMG(JPackageCommand cmd) { // DMG always unsigned, so we will check it Path outputBundle = cmd.outputBundle(); - SigningBase.verifyCodesign(outputBundle, false); + SigningBase.verifyDMG(outputBundle); } private static void verifyAppImageInDMG(JPackageCommand cmd) { diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java index 3126c3f8b99..cedd0721b25 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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,35 +44,67 @@ public class SigningBase { KEYCHAIN = (value == null) ? "jpackagerTest.keychain" : value; } + // Note: It is not clear if we can combine "--verify" and "--display", so + // we testing them separately. Since JDK-8298488 unsigned app images are + // actually signed with adhoc signature and it will pass "--verify", so in + // addition we will check certificate name which was used to sign. + private static enum CodesignCheckType { + VERIFY, // Runs codesign with "--verify" to check signature and 0 exit code + VERIFY_UNSIGNED, // Runs codesign with "--verify" to check signature and 1 exit code + DISPLAY // Runs codesign with "--display --verbose=4" to get info about signature + }; + private static void checkString(List result, String lookupString) { TKit.assertTextStream(lookupString).predicate( (line, what) -> line.trim().contains(what)).apply(result.stream()); } - private static List codesignResult(Path target, boolean signed) { - int exitCode = signed ? 0 : 1; - List result = new Executor() - .setExecutable("/usr/bin/codesign") - .addArguments("--verify", "--deep", "--strict", "--verbose=2", - target.toString()) - .saveOutput() - .execute(exitCode).getOutput(); - - return result; + private static List codesignResult(Path target, CodesignCheckType type) { + int exitCode = 0; + Executor executor = new Executor().setExecutable("/usr/bin/codesign"); + switch (type) { + case CodesignCheckType.VERIFY_UNSIGNED: + exitCode = 1; + case CodesignCheckType.VERIFY: + executor.addArguments("--verify", "--deep", "--strict", + "--verbose=2", target.toString()); + break; + case CodesignCheckType.DISPLAY: + executor.addArguments("--display", "--verbose=4", target.toString()); + break; + default: + TKit.error("Unknown CodesignCheckType: " + type); + break; + } + return executor.saveOutput().execute(exitCode).getOutput(); } private static void verifyCodesignResult(List result, Path target, - boolean signed) { + boolean signed, CodesignCheckType type) { result.stream().forEachOrdered(TKit::trace); - if (signed) { - String lookupString = target.toString() + ": valid on disk"; - checkString(result, lookupString); - lookupString = target.toString() + ": satisfies its Designated Requirement"; - checkString(result, lookupString); - } else { - String lookupString = target.toString() - + ": code object is not signed at all"; - checkString(result, lookupString); + String lookupString; + switch (type) { + case CodesignCheckType.VERIFY: + lookupString = target.toString() + ": valid on disk"; + checkString(result, lookupString); + lookupString = target.toString() + ": satisfies its Designated Requirement"; + checkString(result, lookupString); + break; + case CodesignCheckType.VERIFY_UNSIGNED: + lookupString = target.toString() + ": code object is not signed at all"; + checkString(result, lookupString); + break; + case CodesignCheckType.DISPLAY: + if (signed) { + lookupString = "Authority=" + APP_CERT; + } else { + lookupString = "Signature=adhoc"; + } + checkString(result, lookupString); + break; + default: + TKit.error("Unknown CodesignCheckType: " + type); + break; } } @@ -132,8 +164,24 @@ public class SigningBase { } public static void verifyCodesign(Path target, boolean signed) { - List result = codesignResult(target, signed); - verifyCodesignResult(result, target, signed); + List result = codesignResult(target, CodesignCheckType.VERIFY); + verifyCodesignResult(result, target, signed, CodesignCheckType.VERIFY); + + result = codesignResult(target, CodesignCheckType.DISPLAY); + verifyCodesignResult(result, target, signed, CodesignCheckType.DISPLAY); + } + + // Since we no longer have unsigned app image, but we need to check + // DMG which is not adhoc or certificate signed and we cannot use verifyCodesign + // for this. verifyDMG() is introduced to check that DMG is unsigned. + // Should not be used to validated anything else. + public static void verifyDMG(Path target) { + if (!target.toString().toLowerCase().endsWith(".dmg")) { + TKit.error("Unexpected target: " + target); + } + + List result = codesignResult(target, CodesignCheckType.VERIFY_UNSIGNED); + verifyCodesignResult(result, target, false, CodesignCheckType.VERIFY_UNSIGNED); } public static void verifySpctl(Path target, String type) { diff --git a/test/jdk/tools/jpackage/share/AppContentTest.java b/test/jdk/tools/jpackage/share/AppContentTest.java index 666fafb7168..b31a6e637b2 100644 --- a/test/jdk/tools/jpackage/share/AppContentTest.java +++ b/test/jdk/tools/jpackage/share/AppContentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -99,7 +99,7 @@ public class AppContentTest { } }) - // On macOS aarch64 we always signing app image and signing will fail, since + // On macOS we always signing app image and signing will fail, since // test produces invalid app bundle. .setExpectedExitCode(testPathArgs.contains(TEST_BAD) || TKit.isOSX() ? 1 : 0) .run(); diff --git a/test/jdk/tools/jpackage/share/AppImagePackageTest.java b/test/jdk/tools/jpackage/share/AppImagePackageTest.java index 491182b50ab..4f229e5c934 100644 --- a/test/jdk/tools/jpackage/share/AppImagePackageTest.java +++ b/test/jdk/tools/jpackage/share/AppImagePackageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -94,7 +94,11 @@ public class AppImagePackageTest { if (TKit.isOSX()) { cmd.addArguments("--mac-package-identifier", name); } - }).run(Action.CREATE, Action.UNPACK); + }) + // On macOS we always signing app image and signing will fail, since + // test produces invalid app bundle. + .setExpectedExitCode(TKit.isOSX() ? 1 : 0) + .run(Action.CREATE, Action.UNPACK); // default: {CREATE, UNPACK, VERIFY}, but we can't verify foreign image }