使用 jpackage 实用程序的代码签名 + 公证不适用于 macOS
Code signing + notarization using jpackage utility isn't working on macOS
在某些情况下,我正在使用 jpackage 实用程序尝试创建一个签名的 DMG 文件以交付给我的用户。我需要签署此 DMG 的原因是因为我想对软件进行公证。 By the way, I'm not sure if notarization is possible (yet) using jpackage but I'm trying it anyway.
但是,我在使用 jpackage 的内置代码签名选项时遇到问题,这是成功公证的先决条件。
我是 运行 jpackage 使用选项 --mac-sign --mac-package-signing-prefix CardrDebate --mac-signing-key-user-name "Developer ID Application: ********** (*******)"
(我已经编辑了实际的开发者 ID,因为这是 Whosebug 上的 public)。
创建 jpackage 应用程序图像后,我通过导航到几个生成的 .dylib 文件并尝试 codesign -vvv {filename}.dylib
来测试生成的代码是否实际签名,并且代码签名说对象根本没有签名(并不是说签名不正确,而是根本就没有签名)。
因此,我认为我的问题是我(可能)错误地使用了 macOS 上的 jpackage 签名选项。我应该如何使用这些?
我会继续回答我自己的问题,因为我最终弄清楚了如何签署我的应用程序并通过 Apple 公证服务成功公证它(我的产品是 http://cardr.x10.bz)。
使用 jpackage 的 app-image 选项生成未签名的应用程序包。
使用自动 bash 脚本对应用程序包内的所有 dylib 和可执行文件进行代码签名,使用 codesign -vvv --options runtime --deep --force --sign "Developer ID Application: ********" <filename>
.
这是一个多步骤的过程,所以我将它分成 A/B/C。
3A) 在 MyApp.app/Contents/mods/ 中找到所有包含嵌入式 .dylib 文件的 jar 文件,并将这些文件提取到特定文件夹(或编写一个小程序来为您执行此操作)。对我来说,我的应用程序依赖于 JavaFX,因此许多 JavaFX 库都在 jar 文件中包含 .dylib 文件。但是,如果您只是使用默认的 Java 库,您应该可以跳到第 4 步,因为默认的 Java 库不包含 .dylib 文件。我们需要执行此步骤的原因是因为 Apple 的公证服务也会检查这些嵌入式 .dylib 文件以进行代码签名。
3B) 使用自动 bash 脚本对您刚刚提取的所有 dylib 文件进行代码签名,使用 codesign -vvv --options runtime --deep --force --sign "Developer ID Application: ********" <filename>
.
3C) 将每个已签名的 .dylib 文件添加回各自的 jar 文件中,以替换原始的未签名嵌入式 .dylib 文件。这是一个可能会派上用场的命令:jar uf <path to jar file> <path to dylib file>
。请注意指定的第二个路径,dylib 文件的路径,也应该是 dylib 在存档中的相对位置。在这里查看更多详细信息 - https://docs.oracle.com/javase/tutorial/deployment/jar/update.html.
现在您已经对 .app 中的每个可执行文件和 dylib 文件进行了签名,是时候对 .app 本身进行签名了。 运行 codesign -vvv --force --sign "Developer ID Application: ********" MyApp.app
.
现在您已经签署了 .app,您需要 运行 对应用程序包进行 jpackage 以从中创建 DMG 或 PKG。随意使用 jpackage mac 签名功能,它将对外部 DMG/PKG 进行签名。请注意 属性 --mac-signing-key-user-name "My Developer Account Name (*******)"
不应包含证书的 "Developer ID Application/Installer" 部分。
最后,您已经创建了一个已签名的 PKG/DMG 准备好进行公证。使用 xcrun altool --notarize-app --username <apple-id> --password <app-specific-password> <MyApp.dmg or MyApp.pkg>
。等待公证完成并确保它被批准。
如果公证成功(它应该),您可以使用 xcrun stapler staple MyApp.pkg
.
将您的应用程序票据装订到 PKG 安装程序
希望对您有所帮助!
对于我的应用程序的有效端到端脚本(Unattach), see the darwin
section of package.sh。
仅供参考 - 在 JDK 14.0.1 中深入研究了这个问题,并希望将知识作为另一个临时解决方案分享,直到 jpackage 正常工作。
在JDK14源路径:src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal
文件 MacAppBundler.java 包含这些行(81 和 82):
"Developer ID Application: "
+ SIGNING_KEY_USER.fetchFrom(参数),
其中 SIGNING_KEY_USER 从命令行获取 --mac-signing-key-user-name 参数的值。
在这些行中,使用 jpackage 签署 DMG 总是失败。 ('Developer ID Application: ' 与我的证书名称不匹配。)
更改了这些行以删除 "Developer ID Application: " 和后面的“+”符号。在调用 jpackage 时使用证书的全名作为参数值:
--mac-signing-key-user-name“第 3 方 Mac 开发者应用程序:John Smith (ABCDEFGHIJ)”
jpackage 现在(显然)将构建并签署 DMG。 没有实际尝试将此提交到 Apple Store,因此这可能仍然不完整。
有趣的是,MacAppStoreBundler.java 源确实包含正确的“第 3 方 Mac 开发人员应用程序:”和“第 3 方 Mac 开发人员安装程序:“前缀字符串,所以怀疑 jpackager 实际上调用了错误的方法——但还没有解决这个问题。可能 jpackage 需要一些额外的参数来准确指定应该做什么(但你会认为 '--type dmg' 会调用正确的逻辑)。
重现的基本(笨拙)步骤:
- 从 https://hg.openjdk.java.net/jdk 下载源代码(选择 jdk14,
提交 6c954123ee8d).
- 下载 .zip(或 .gz 或 .bz2)并将其解压到工作目录
- 使用任何文本编辑器按照 'src' 的路径并如上所述更改 MacAppBundler.java。
- 打开终端window,cd进入'src'目录
- 运行 'make all'编译整个JDK 14
- 运行 src/build/macosx-x86_64-server-release/images/jdk/bin/jpackage ...参数...
我只想更新一下流程。我有一个 JavaFX 11 应用程序,在构建过程中使用 Java 16。所描述的 Soham 方法有效。但是,我发现了一些要点:
- 使用 Java 16,您不再需要“--deep”选项来签署应用程序映像(也不建议部署)。
- 我需要用于签名的权利文件,即用于签名的 --entitlement 选项。否则应用程序在签名后不会启动。
- 可以使用 jpackage 签名参数对安装程序进行签名。
- 以 zip 格式上传安装程序以进行公证按预期工作。
另一个更新:使用 JavaFX/JDK 17.0.2,我能够构建一个 .dmg 文件,如下所示。然后可以将此文件上传到网络服务器,并使用网络浏览器下载:
# no entitlements required.
# no further .dylib or .jar signing required.
jpackage --type dmg --mac-sign --mac-signing-key-user-name "YOUR_DEVELOPER_APPLICATION_ID" [...]
# .dmg signing is required for notarization.
codesign --timestamp -s "YOUR_DEVELOPER_APPLICATION_ID" "DMG_NAME"
# recommended notarization steps with verification
xcrun notarytool submit "DMG_NAME" --wait --keychain-profile "YOUR_PROFILE"
xcrun stapler staple "DMG_NAME"
spctl -a -t open --context context:primary-signature -vv "DMG_NAME"
在某些情况下,我正在使用 jpackage 实用程序尝试创建一个签名的 DMG 文件以交付给我的用户。我需要签署此 DMG 的原因是因为我想对软件进行公证。 By the way, I'm not sure if notarization is possible (yet) using jpackage but I'm trying it anyway.
但是,我在使用 jpackage 的内置代码签名选项时遇到问题,这是成功公证的先决条件。
我是 运行 jpackage 使用选项 --mac-sign --mac-package-signing-prefix CardrDebate --mac-signing-key-user-name "Developer ID Application: ********** (*******)"
(我已经编辑了实际的开发者 ID,因为这是 Whosebug 上的 public)。
创建 jpackage 应用程序图像后,我通过导航到几个生成的 .dylib 文件并尝试 codesign -vvv {filename}.dylib
来测试生成的代码是否实际签名,并且代码签名说对象根本没有签名(并不是说签名不正确,而是根本就没有签名)。
因此,我认为我的问题是我(可能)错误地使用了 macOS 上的 jpackage 签名选项。我应该如何使用这些?
我会继续回答我自己的问题,因为我最终弄清楚了如何签署我的应用程序并通过 Apple 公证服务成功公证它(我的产品是 http://cardr.x10.bz)。
使用 jpackage 的 app-image 选项生成未签名的应用程序包。
使用自动 bash 脚本对应用程序包内的所有 dylib 和可执行文件进行代码签名,使用
codesign -vvv --options runtime --deep --force --sign "Developer ID Application: ********" <filename>
.这是一个多步骤的过程,所以我将它分成 A/B/C。
3A) 在 MyApp.app/Contents/mods/ 中找到所有包含嵌入式 .dylib 文件的 jar 文件,并将这些文件提取到特定文件夹(或编写一个小程序来为您执行此操作)。对我来说,我的应用程序依赖于 JavaFX,因此许多 JavaFX 库都在 jar 文件中包含 .dylib 文件。但是,如果您只是使用默认的 Java 库,您应该可以跳到第 4 步,因为默认的 Java 库不包含 .dylib 文件。我们需要执行此步骤的原因是因为 Apple 的公证服务也会检查这些嵌入式 .dylib 文件以进行代码签名。
3B) 使用自动 bash 脚本对您刚刚提取的所有 dylib 文件进行代码签名,使用 codesign -vvv --options runtime --deep --force --sign "Developer ID Application: ********" <filename>
.
3C) 将每个已签名的 .dylib 文件添加回各自的 jar 文件中,以替换原始的未签名嵌入式 .dylib 文件。这是一个可能会派上用场的命令:jar uf <path to jar file> <path to dylib file>
。请注意指定的第二个路径,dylib 文件的路径,也应该是 dylib 在存档中的相对位置。在这里查看更多详细信息 - https://docs.oracle.com/javase/tutorial/deployment/jar/update.html.
现在您已经对 .app 中的每个可执行文件和 dylib 文件进行了签名,是时候对 .app 本身进行签名了。 运行
codesign -vvv --force --sign "Developer ID Application: ********" MyApp.app
.现在您已经签署了 .app,您需要 运行 对应用程序包进行 jpackage 以从中创建 DMG 或 PKG。随意使用 jpackage mac 签名功能,它将对外部 DMG/PKG 进行签名。请注意 属性
--mac-signing-key-user-name "My Developer Account Name (*******)"
不应包含证书的 "Developer ID Application/Installer" 部分。最后,您已经创建了一个已签名的 PKG/DMG 准备好进行公证。使用
xcrun altool --notarize-app --username <apple-id> --password <app-specific-password> <MyApp.dmg or MyApp.pkg>
。等待公证完成并确保它被批准。如果公证成功(它应该),您可以使用
xcrun stapler staple MyApp.pkg
. 将您的应用程序票据装订到 PKG 安装程序
希望对您有所帮助!
对于我的应用程序的有效端到端脚本(Unattach), see the darwin
section of package.sh。
仅供参考 - 在 JDK 14.0.1 中深入研究了这个问题,并希望将知识作为另一个临时解决方案分享,直到 jpackage 正常工作。
在JDK14源路径:src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal
文件 MacAppBundler.java 包含这些行(81 和 82): "Developer ID Application: " + SIGNING_KEY_USER.fetchFrom(参数),
其中 SIGNING_KEY_USER 从命令行获取 --mac-signing-key-user-name 参数的值。
在这些行中,使用 jpackage 签署 DMG 总是失败。 ('Developer ID Application: ' 与我的证书名称不匹配。)
更改了这些行以删除 "Developer ID Application: " 和后面的“+”符号。在调用 jpackage 时使用证书的全名作为参数值:
--mac-signing-key-user-name“第 3 方 Mac 开发者应用程序:John Smith (ABCDEFGHIJ)”
jpackage 现在(显然)将构建并签署 DMG。 没有实际尝试将此提交到 Apple Store,因此这可能仍然不完整。
有趣的是,MacAppStoreBundler.java 源确实包含正确的“第 3 方 Mac 开发人员应用程序:”和“第 3 方 Mac 开发人员安装程序:“前缀字符串,所以怀疑 jpackager 实际上调用了错误的方法——但还没有解决这个问题。可能 jpackage 需要一些额外的参数来准确指定应该做什么(但你会认为 '--type dmg' 会调用正确的逻辑)。
重现的基本(笨拙)步骤:
- 从 https://hg.openjdk.java.net/jdk 下载源代码(选择 jdk14, 提交 6c954123ee8d).
- 下载 .zip(或 .gz 或 .bz2)并将其解压到工作目录
- 使用任何文本编辑器按照 'src' 的路径并如上所述更改 MacAppBundler.java。
- 打开终端window,cd进入'src'目录
- 运行 'make all'编译整个JDK 14
- 运行 src/build/macosx-x86_64-server-release/images/jdk/bin/jpackage ...参数...
我只想更新一下流程。我有一个 JavaFX 11 应用程序,在构建过程中使用 Java 16。所描述的 Soham 方法有效。但是,我发现了一些要点:
- 使用 Java 16,您不再需要“--deep”选项来签署应用程序映像(也不建议部署)。
- 我需要用于签名的权利文件,即用于签名的 --entitlement 选项。否则应用程序在签名后不会启动。
- 可以使用 jpackage 签名参数对安装程序进行签名。
- 以 zip 格式上传安装程序以进行公证按预期工作。
另一个更新:使用 JavaFX/JDK 17.0.2,我能够构建一个 .dmg 文件,如下所示。然后可以将此文件上传到网络服务器,并使用网络浏览器下载:
# no entitlements required.
# no further .dylib or .jar signing required.
jpackage --type dmg --mac-sign --mac-signing-key-user-name "YOUR_DEVELOPER_APPLICATION_ID" [...]
# .dmg signing is required for notarization.
codesign --timestamp -s "YOUR_DEVELOPER_APPLICATION_ID" "DMG_NAME"
# recommended notarization steps with verification
xcrun notarytool submit "DMG_NAME" --wait --keychain-profile "YOUR_PROFILE"
xcrun stapler staple "DMG_NAME"
spctl -a -t open --context context:primary-signature -vv "DMG_NAME"