Gatekeeper disallowing directly distributed app

This is a continuation of my own old post that became inactive to regain traction. I am trying to resolve issues that arise when distributing a macOS app with a SysExt Network Extension (Packet Tunnel) outside the App Store using a Developer ID Certificate.

To directly distribute the app, I start with exporting the .app via Archive in Xcode. After that, I create a new Developer ID provisioning profile for both the app and sysext and replace the embedded ones in the .app package.

After I have replaced the provisioning profiles and the have the entitlements files ready, I start signing the frameworks, sysext and parent app.

codesign --force --options runtime --timestamp --sign "Developer ID Application: <name>"<app>.app/Contents/Library/SystemExtensions/<sysext>.systemextension/Contents/Frameworks/<fw>.framework/Versions/A/<fw>
codesign --force --options runtime --timestamp --sign "Developer ID Application: <name>" <app>.app/Contents/Frameworks/<fw>.framework/
codesign --force --options runtime --entitlements dist-vpn.entitlements --timestamp --sign "Developer ID Application: <name>" <app>.app/Contents/Library/SystemExtensions/<sysext>.systemextension/Contents/MacOS/<sysext>
codesign --force --options runtime --entitlements dist.entitlements --timestamp --sign "Developer ID Application: <name>" <app>.app

After validation is successful with

codesign --verify --deep --strict --verbose=4 <app>.app

I zip the package, notarize and staple it

ditto -c -k --keepParent "<app>.app" "<app>..zip"
xcrun notarytool submit <app>.zip --keychain-profile “”<credents> --wait
xcrun stapler staple <app>.app

After that I finish creating signed and notarized .dmg/.pkg.

 hdiutil create -volname “<app>” -srcfolder “<app>.app/" -ov -format UDZO ./<app>.dmg
 codesign --force --sign "Developer ID Application: <name>" <app>.dmg
 xcrun notarytool submit <app>.dmg --keychain-profile "<credentials>" --wait
 xcrun stapler staple <app>.dmg

Then when I move the .dmg to a clean system, open the .dmg, move the .app to the Applications folder, the attempt to run it fails with “The application “<app>” can’t be opened.”. When I look into the console, the gatekeeper disallows the launch job with the message:


86127	debug	ProvisioningProfiles	taskgated-helper	ConfigurationProfiles	entitlements: {
    "com.apple.developer.networking.networkextension" =     (
        "packet-tunnel-provider-systemextension"
    );
    "com.apple.developer.system-extension.install" = 1;
    "com.apple.developer.team-identifier" = <teamid>;
    "keychain-access-groups" =     (
        “<teamid>.<app>.AppGroup"
    );
}	com.apple.ManagedClient
<app>: Unsatisfied entitlements: com.apple.developer.networking.networkextension, keychain-access-groups, com.apple.developer.system-extension.install, com.apple.developer.team-identifier
LAUNCH: Runningboard launch of <app> <private> returned RBSRequestErrorFailed, error Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x600001a25830 {Error Domain=NSPOSIXErrorDomain Code=153 "Unknown error: 153" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}, so returning -10810



I went through all possible formats (macOS-Style and iOS-Style App Group IDs) and combinations of appgroups according to the post “App Groups: macOS vs iOS: Working Towards Harmony”. But none of those work for me. The weird part is that when I try the same steps on different developer account, I am able to get the app running. What can be wrong?

Answered by DTS Engineer in 846382022

Sorry I dropped the ball on your earlier thread. I wasn’t notified of your update. Still, it looks like you’ve made some progress since then, which is good.

The immediate cause of the error is that your app is using restricted entitlements that aren’t authorised by a provisioning profile. However, that just leads to the next question: Why isn’t the profile that you’ve embedded effective?

There’s a trivially correct answer to that, but it’s not the full story. Your app is missing the App ID entitlement (com.apple.application-identifier). As explained in TN3125 Inside Code Signing: Provisioning Profiles, that entitlement is used to tie your app to its profile, so the absence of that is something you need to fix.

But, that’s not the full story because macOS 12 and later will assume that the profile embedded in the app is the right profile for that app. So the missing App ID entitlement typically only bites folks when they go to test their apps on macOS 11 or earlier.

And that brings me to this:

The weird part is that when I try the same steps on different developer account, I am able to get the app running.

This doesn’t make sense to me. Imagine if you’d correctly applied the App ID entitlement. Then the App ID of each of your code items would be registered to a specific team. That App ID embeds the bundle ID, so the bundle ID is also effectively registered to that team. If you take an app from team A and try to re-sign it as team B, that’s not going to work without you changing the bundle ID along the way. Specifically:

  • For the app to connect to its profile, it needs to be signed with the App ID entitlement.

  • The value of that App ID entitlement must match the value in the profile.

  • The profile ties together a bunch of things, including the App ID and the authorised certificates.

  • But it’s impossible to create a profile for team B that authorises an App ID that’s registered team A. The Developer website won’t let you do that, and for good reason: The clear ownership of App IDs is a foundation of Apple’s code signing security model.

The only way to achieve your goal is to change the bundle ID, which changes the App ID, which you can register to team B, and from there generate a valid profile.

This was exactly the issue I was trying to explain in your earlier thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Sorry I dropped the ball on your earlier thread. I wasn’t notified of your update. Still, it looks like you’ve made some progress since then, which is good.

The immediate cause of the error is that your app is using restricted entitlements that aren’t authorised by a provisioning profile. However, that just leads to the next question: Why isn’t the profile that you’ve embedded effective?

There’s a trivially correct answer to that, but it’s not the full story. Your app is missing the App ID entitlement (com.apple.application-identifier). As explained in TN3125 Inside Code Signing: Provisioning Profiles, that entitlement is used to tie your app to its profile, so the absence of that is something you need to fix.

But, that’s not the full story because macOS 12 and later will assume that the profile embedded in the app is the right profile for that app. So the missing App ID entitlement typically only bites folks when they go to test their apps on macOS 11 or earlier.

And that brings me to this:

The weird part is that when I try the same steps on different developer account, I am able to get the app running.

This doesn’t make sense to me. Imagine if you’d correctly applied the App ID entitlement. Then the App ID of each of your code items would be registered to a specific team. That App ID embeds the bundle ID, so the bundle ID is also effectively registered to that team. If you take an app from team A and try to re-sign it as team B, that’s not going to work without you changing the bundle ID along the way. Specifically:

  • For the app to connect to its profile, it needs to be signed with the App ID entitlement.

  • The value of that App ID entitlement must match the value in the profile.

  • The profile ties together a bunch of things, including the App ID and the authorised certificates.

  • But it’s impossible to create a profile for team B that authorises an App ID that’s registered team A. The Developer website won’t let you do that, and for good reason: The clear ownership of App IDs is a foundation of Apple’s code signing security model.

The only way to achieve your goal is to change the bundle ID, which changes the App ID, which you can register to team B, and from there generate a valid profile.

This was exactly the issue I was trying to explain in your earlier thread.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@DTS Engineer

Thank you for your reply.

Regarding:

The weird part is that when I try the same steps on different developer account, I am able to get the app running.

That also included changing the Developer ID certificates, Team ID, Bundle ID, App Groups, provisioning profiles, and entitlements to match the updated IDs. I used the same format for App Groups and did not add any new entitlements.

As for the com.apple.application-identifier entitlement:

When I export the .app, the entitlements and provisioning profiles built into the package contain the App ID entitlement. The provisioning profiles used to replace the existing profiles also include this entitlement, as do the updated entitlements with the -systemextension suffix.

When I check the entitlements of the signed app from the generated .dmg bundle, it also contains the com.apple.application-identifier entitlement.

Is there another place where this entitlement might be required that I could be missing? Thank you.

That also included changing the Developer ID certificates, Team ID, Bundle ID, App Groups, provisioning profiles, and entitlements to match the updated IDs.

Changing all of that correctly is quite challenging.

My recommendation is that start by create a small test app with which to bring up the tool (well, script, right?) you’ve built to make this change. You can start simple and then add additional bits, testing as you go. For example, you could start with a simple app — just the app, no extensions — that claims no restricted entitlements. Then extend that to claim a single restricted entitlement, like com.apple.developer.system-extension.install. Then keep extending it until it looks like your real app.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Gatekeeper disallowing directly distributed app
 
 
Q