Taskgated-helper ignores embedded.provisionprofile

I'm working on an app using entitlements. The entitlements are setup in its code signature and they are also applied in the corresponding provisioning profile.

I embed said provisioning profile in the app, but when I launch the binary it gets rejected by taskgated-helper (as seen in console.app it says "profile not found").

However, if I install the same embedded provision profile it will work! So I can only assume taskgated-helper is not looking in the Contents/embedded.provisionprofile file when I try to run the binary?

I can only imagine that the issue revolves around the binary not being the main bundle binary in the application, as that one works just fine without installing the profile.

I would simply install the profile to fix the issue, but it brings other problems when trying to install the application in a headless environment (as opening the profile to install in system settings requires user interaction).

Any ideas?

Replies

I can only imagine that the issue revolves around the binary not being the main bundle binary in the application

Can you elaborate on that? What does your bundle structure look like?

Share and Enjoy

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

Thanks for your reply, the project structure looks like this:

└── Contents
    ├── Frameworks
    │   └── ...
    ├── Info.plist
    ├── Library
    │   ├── LaunchServices
    │   └── SystemExtensions
    ├── MacOS
    │   ├── ApplicationClient
    │   └── ApplicationDaemon
    ├── PkgInfo
    ├── PlugIns
    │   └── ...
    ├── Resources
    │   └── LICENSE.txt
    ├── _CodeSignature
    │   └── CodeResources
    └── embedded.provisionprofile

ApplicationClient is the client app that launches when double clicking the app . This one runs fine when double clicking the app icon or when running from terminal. It's set in the Info.plist file as the bundle executable, which is what I suspected would cause the issue:

	<key>CFBundleExecutable</key>
	<string>Private Internet Access</string>

ApplicationDaemon is set up to run as a launchctl daemon or can be run from the terminal. But, after adding the system extension entitlements, this binary won't run either from the terminal or as daemon, with an error from taskgated-helper (as seen in console.app) saying that it cannot find the matching provision profile, even though the bundle ID is reported as the same as the ApplicationClient.

The strange part for me is that if the profile is installed manually (which I understand is an outdated way of doing things and we should use embedded.provisionprofile) it does get picked up immediately and taskgated-helper won't block it anymore.

Thanks for the help!

  • Well, it was supposed to look like this

    <key>CFBundleExecutable</key>
    <string>ApplicationClient</string>
    
  • I've now confirmed that if I change the plist file CFBundleExecutable to the ApplicationDaemon instead of the ApplicationClient, then the ApplicationDaemon runs fine with the profile uninstalled, but the client does not, requiring the profile to be set if I want entitlements to work for it.

Add a Comment

ApplicationDaemon is set up to run as a launchd daemon

I suspect that ApplicationDaemon is a standalone executable, that is, it’s not wrapped in its own bundle structure. Standalone executables can’t use restricted entitlements because there’s no place to store the associated provisioning profile [1].

To get around this you have to embed your daemon into its own app-like wrapper. For advice on how to do this, see Signing a daemon with a restricted entitlement.

IMPORTANT For this to work reliably, your app and its embedded daemon must use a different bundle ID, and thus a different App ID. The App ID is how the system confirms that the embedded profile is valid for the app [2] in which it’s embedded. That also means that both need their own unique provisioning profile. See TN3125 Inside Code Signing: Provisioning Profiles for more background on how profiles actually work.

You can leave the resulting daemon-in-an-app-like-wrapper in Contents/MacOS or move it to Contents/Helpers. Either location is fine, per the guidance in Placing Content in a Bundle.

Share and Enjoy

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

[1] The profile you’ve placed in Contents/embedded.provisionprofile applies to the main application bundle.

[2] Well, in this case the daemon pretending to be an app.

  • Thanks! I'll give that a try/

Add a Comment

I packaged the Daemon as a separate app bundle within and it works during development. However, once I sign it with my developer ID certificate for distribution the network extension will not activate, getting stuck the activation request and completely killing any internet connectivity until I restart.

The only thing that I see is different is when I call systemextensionsctl list I get something like:

1 extension(s)
--- com.apple.system_extension.network_extension
enabled	active	teamID	bundleID (version)	name	[state]
		<TEAM_ID>	com.company.networkExt (1.0/240116145656)	-	[validating by category]
*	*	<TEAM_ID>	com.company.networkExt (1.0/240115061310)	ProxyExtension	[activated enabled]

Where the one specifying [validating by category] is the one that I'm trying to activate signed with the developer ID cert. The one that is [activated enabled] got there from a dev build.

The app was built and notarized and shows to be valid by any codesign -dv --verify --strict and spctl commands that I've found. The system extension is valid according to codesign, but spctl --verbose=4 --assess does report:

com.company.vpn.networkExt.systemextension: rejected (the code is valid but does not seem to be an app)

See my response on your other thread.

Share and Enjoy

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