为 MacOS Catalina 公证现有 Java 应用程序

Notarize existing Java application for MacOS Catalina

我为 MacOS 分发了一个 Java 应用程序,它是开发人员签名但未经过公证的。不太确定从哪里开始,因为文档非常偏向于使用我不使用的 Xcode 创建应用程序,但我只想要最简单的方法来公证我的应用程序然后继续。

阅读文档后我已经有了一些顾虑:

公证需要 Xcode10,装订至少需要 Sierra.

“公证需要 Xcode 10 或更高版本。构建用于公证的新应用程序需要 macOS 10.13.6 或更高版本。装订应用程序需要 macOS 10.12 或更高版本。” https://developer.apple.com/documentation/security/notarizing_your_app_before_distribution

至于转移开发证书,让 Xcode 通过在旧机器上导出您的配置文件并在新机器上导入来处理此任务。

  • AFAIK,你需要 Java 11(参见 JDK-8223671), however, recently I was told Java 8 也可以。我没试过这个。

  • JDK-8223671 包含一些有用的信息。具体来说,您需要为您的代码签名调用添加权利:

codesign --entitlements java.entitlements --options runtime --deep -vvv -f --sign "Developer ID Application: Bla Bla (XXXX)" YourApp.app

工作示例 java.entitlements 文件可能如下所示:

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0"> 
<dict> 
    <key>com.apple.security.cs.allow-jit</key> 
    <true/> 
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key> 
    <true/> 
    <key>com.apple.security.cs.disable-executable-page-protection</key> 
    <true/> 
    <key>com.apple.security.cs.disable-library-validation</key> 
    <true/> 
    <key>com.apple.security.cs.allow-dyld-environment-variables</key> 
    <true/> 
</dict> 
</plist> 
  • 捆绑一个 jlink 生成的运行时是一件痛苦的事情,因为它包含符号链接(在签名期间不允许)以及一个包含文件夹名称的合法文件夹 java.xml(带有 .)。不幸的是,codesign 有点笨,认为此类文件夹是无法识别的捆绑包并中止。因此,您应该重命名那些 files/folders 并在 jlinking 之前解析任何 sim 链接。

  • 如果您使用 jlink,请确保添加所需的服务提供商,例如 。另请注意,AFAIK,在 Java 11 TLSv1.3 中至少部分损坏(上传大文件),您应该禁用它,例如-Dhttps.protocols=TLSv1.1,TLSv1.2.

  • 如果您使用 AppBundler 分支,您将需要确保它也符合 Apple 的指导方针,即链接到 macOS 10.9。我相信默认情况下 AppBundler 链接到 10.7,但更改它很简单。

  • 如果您使用的是 Java 11 或更高版本,请确保将 libjli.dylib 捆绑在 /Contents/PlugIns/JAVA_PLUGIN_NAME/Contents/Home/lib/jli/libjli.dylib 中。显然,启动器需要它,默认情况下可能不会捆绑。

  • 您的其他一些问题已在 Apple guidelines:

  • 中得到解答

Notarization requires Xcode 10 or later. Building a new app for notarization requires macOS 10.13.6 or later. Stapling an app requires macOS 10.12 or later.

编辑 12/2/2020 - 由于 Apple 慢慢收紧了公证要求,因此发生了很多变化。从 2 月 3 日开始,它们似乎进入了最后阶段,这意味着您的应用程序必须满足更高的要求,包括针对最新 SDK 构建并具有 "hardened runtime" 支持的 JRE。

所以我删除了很多旧的讨论。

我的第一个问题是设置 - 您需要一个具有 Apple ID 的有效开发者计划帐户(这很容易),但是当您按照说明将密码添加到钥匙串时,请使用 应用专用密码。您还需要为您的 Apple ID 帐户启用双重身份验证。

一旦计算出命令行调用,就很容易在构建脚本中实现自动化。我已经使用 jpackage 创建了应用程序和 DMG,但请注意 - currently its approach to signing the app does not work.

就脚本而言,以下是我正在对适用于公证的应用程序进行代码签名的操作(假设已经创建了 .app):

% security unlock-keychain -p passwordhere codesigning.keychain
% find my-app.app -type f \
  -not -path "*/Contents/runtime/*" \
  -not -path "*/Contents/MacOS/my-app" \
  -not -path "*libapplauncher.dylib" \
  -exec codesign --timestamp --entitlements /tmp/bliss.entitlements -s "XXX" --prefix com.myapp. --options runtime -v --keychain /path/to/codesigning.keychain {} \;

% find my-app.app/Contents/runtime -type f \
  -not -path "*/legal/*" \
  -not -path "*/man/*" \
  -exec codesign -f --timestamp --entitlements /tmp/bliss.entitlements -s "XXX" --prefix com.myapp. --options runtime -v --keychain /path/to/codesigning.keychain {} \;

% codesign -f --timestamp --entitlements /tmp/bliss.entitlements -s "XXX" --prefix com.myapp. --options runtime -v --keychain /path/to/codesigning.keychain my-app.app/Contents/runtime

% codesign -f --timestamp --entitlements /tmp/bliss.entitlements -s "XXX" --prefix com.myapp. --options runtime -v --keychain /path/to/codesigning.keychain my-app.app

权利应该是:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
</dict>
</plist>

所有测试都有效:

% codesign -vvv --deep --strict my-app.app/Contents/runtime 
my-app.app/Contents/runtime: valid on disk
my-app.app/Contents/runtime: satisfies its Designated Requirement
% codesign -vvv --deep --strict my-app.app/                
--prepared:/private/tmp/my-app.app/Contents/MacOS/libapplauncher.dylib
--validated:/private/tmp/my-app.app/Contents/MacOS/libapplauncher.dylib
my-app.app/: valid on disk
my-app.app/: satisfies its Designated Requirement
% spctl -a -t exec -vv my-app.app          
my-app.app: accepted
source=Developer ID
origin=XXX

此时您还应该尝试 运行 您的应用程序 - 代码签名过程可能会破坏某些东西。

从这里,您可以创建一个 DMG(同样,我使用 jpackage)并且这应该通过公证。

总结:

  1. 以正确的结构构建应用程序
  2. 创建权利文件
  3. 代码签名你的代码
  4. 在捆绑运行时内对文件进行代码签名,强制签名
  5. 对捆绑的运行时本身进行代码签名
  6. 对您的应用文件进行代码签名
  7. 打包成DMG
  8. 公证
  9. 发货

截至 2020 年 2 月 3 日的更新 Apple 收紧了公证要求,重写了答案。

注意:我需要 AdoptJdk Java 11.0.7 JRE,早期版本不适合我。

这些是我的步骤

  • 设置新机器(设置src代码ectera)
  • 安装 XCode 然后转到 Preferences:Downloads 和 select 安装命令行工具
  • 使用 KeyChain 将 Developer Id 证书导出为 .p12 格式并导入新机器
  • 购买并安装 DmgCanvas 3 ($30USD)
  • 续订 Apple 开发者帐户
  • 为我的 AppleId 帐户设置两步授权(部分在网站上完成,部分使用 iCloud 应用程序完成)
  • 创建应用专用密码(记下 dmgCanvas 选项所需的密码)
  • 安装 AdoptJdk Java 11.0.7 构建
  • 安装 AdoptJdk Java 11.0.7 JRE 用于在应用程序中捆绑
  • 创建songkong.entitlements 文件
  • 配置 build.xml Appbundler InfiniteKind 分支使用的文件以直接引用 AdoptOpenJDK JRe build
  • 配置构建脚本以对 appbundler 创建的包进行签名,确保我们使用所需的新签名选项(例如 -runtime、--entitlements、--timestamp)
  • 构建脚本然后使用 dmgCanvas 创建一个 dmg,这会额外签署 dmg 并将其发送给 Apple 进行公证

build.xml 包括:

<runtime dir="/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jre/Contents/Home"/>

buildosx.sh 是

#!/bin/bash
#set -x

cd /Users/paul/code/jthink/songkong
sudo rm -fr /Applications/SongKong.app
mvn -f pommacos.xml -DskipTests=true install
rm -fr target/songkong-6.9
unzip target/songkong-6.9-distribution.zip -d target
ant
export CODESIGN_ALLOCATE="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate"
/usr/bin/codesign --timestamp --options runtime \
--entitlements /Users/paul/code/jthink/songkong/songkong.entitlements \
--sign "Developer ID Application: P Taylor" \
--force --deep --verbose /Applications/SongKong.app
/usr/bin/codesign -vvv --deep --strict /Applications/SongKong.app
spctl -a -t exec -vv /Applications/SongKong.app
cd /Users/paul/code/jthink/SongKong
/usr/local/bin/dmgcanvas /Users/paul/code/jthink/SongKong/dmgCanvas_songkong.dmgCanvas \
 /Users/paul/songkong-osx.dmg \
 -v SongKong -identity "Developer ID Application: P Taylor" \
 -notarizationAppleID paultaylor@jthink.net \
 -notarizationPassword password \
 -notarizationPrimaryBundleID songkong

SongKong 权利文件是:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>com.apple.security.cs.allow-jit</key>
    <true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
    <true/>
    <key>com.apple.security.cs.disable-executable-page-protection</key>
    <true/>
    <key>com.apple.security.cs.disable-library-validation</key>
    <true/>
    <key>com.apple.security.cs.allow-dyld-environment-variables</key>
    <true/>
</dict>
</plist>

注意:我也尝试过参考 AdoptJdk Java 11.0.7 JDK build.xml 并且构建也没有问题(当然最终会得到更大的伤害)