Signed macOS programs with Java 14

Since February 2020 Apple requires all programs to be signed, hardened and notarized so that the Gatekeeper on macOS Catalina allows them to be run. Before it was only necessary to sign them so Java 8 could still be used. Now they have to be hardened, with requires XCode 10 and Java 8 cannot be compiled with XCode 10 yet so a newer Java version has to be used. Java 14 contains the “jpackage” program to create a native signed app that can fulfill these requirements (with some additional work).

First you have to build your program, e.g. with maven

mvn package

Then you have to create an app image using jpackage e.g. this way:

$JAVA_HOME/bin/jpackage -n MyApp --input target --main-jar MyApp-1.0.jar --main-class com.myapp.MyApp --module-path libfx --add-modules javafx.controls,javafx.fxml,javafx.web,javafx.swing,javafx.media --icon src/main/deploy/package/macosx/MyApp.icns --type app-image --dest appimageoutput --java-options "-Xmx1024m"

Afterward you have to sign all jar files and dylib files in the appimageoutput directory. My “SignPackage.jar” simply searches for all dylib and jar files in the given directory (also dylib files inside jar files) and signs them with “codesign –timestamp –options runtime –entitlements … — deep -vvv -f –sign “Developer (XXX)” file”:

java -jar SignPackage.jar -d appimageoutput -t -r -k "Developer ID Application: John Public (XXXXXXXXXX)" -e "src/main/deploy/package/macosx/MyApp.entitlements"

codesign --timestamp --entitlements src/main/deploy/package/macosx/MyApp.entitlements --options runtime --deep -vvv -f --sign "Developer ID Application: John Public (XXXXXXXXXX)" appimageoutput/MyApp.app/Contents/MacOS/*

codesign --timestamp --entitlements src/main/deploy/package/macosx/MyApp.entitlements --options runtime --deep -vvv -f --sign "Developer ID Application: John Public (XXXXXXXXXX)" appimageoutput/MyApp.app

Then you can create a DMG file:

$JAVA_HOME/bin/jpackage -n MyApp --mac-package-identifier com.myapp --mac-package-name MyApp --mac-sign --mac-signing-key-user-name "John Public (XXXXXXXXXX)" --app-image appimageoutput

Sign the DMG file:

codesign --timestamp --entitlements src/main/deploy/package/macosx/MyApp.entitlements --options runtime --deep -vvv -f --sign "Developer ID Application: John Public (XXXXXXXXXX)" MyApp-1.0.dmg

And notarize it:

xcrun altool --notarize-app --primary-bundle-id com.myapp --username john@public.com --password mypassword --file MyApp-1.0.dmg

The entitlements file should probably at least contain these lines:

<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>

A complete “MyApp.entitlements” file could look like this:

<?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.app-sandbox</key>
<false/>
<key>com.apple.security.network.server</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<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>