Can we just add the SystemExtension entitlement to the current App ID
for the network extension, update the profile, and continue with the
same ID, or will we need to define a new ID?
This question doesn’t make sense. An App ID has capabilities which flow into the entitlement allowlist in your provisioning profile. When you create a profile from an App ID with the Network Extension capability enabled, you get different results depending on the type of provisioning profile:
Last I checked, Xcode’s standard code signing infrastructure wasn’t able to handle this subtlety (r. 108838909), which means you need to manually re-sign your app for Developer ID distribution.
What will happen if someone installs the application from a package
outside the app store, and then goes to the app store page for the
application? Will the App Store recognize that the app is already
installed? What about version differences?
It’s not uncommon for Developer ID and App Store apps to have the same bundle ID. In general, macOS treats two apps with the same bundle ID as the same app.
Historically this extended to the App Store upgrade process, where App Store would happily upgrade a Developer ID app. However, I haven’t seen that in a long time. Today I tried it — using Hex Fiend, which has both Developer ID and App Store versions — and App Store was pretty clear about not doing that upgrade, failing with the message:
“Hex Fiend” is Already Installed
To install this app, rename or move “Hex Fiend” from your Applications folder and try again.
[[OK]]
It looks like our management app can still use sendProviderMessage to
communicate with the extension, and that we don't need XPC unless we
want to give other applications the ability to talk with the
extension. Is this correct?
Yes.
However, sysex packaging generally produces more complex interactions between the sysex and its container app, which means it often makes sense to switch to XPC.
Can a System Extension use the NSWorkspace
openURL API?
No. Sysexes are effectively launchd
daemons and it’s only safe for them to use daemon-safe APIs.
Also, this makes no sense conceptually. Your sysex is shared between all the users logged into the system. If it calls -openURL
and multiple GUI users are logged in, in which GUI context would the app open?
It looks like a System Extension doesn't have the option of writing to
a file, because it's not running as a logged in user and doesn't have
access to a user's file systems. Is this correct?
It can write to files, just like any other sandboxed process. The difference is that it’s running as root, so it can’t, say, share an app group container with the app being run by a specific user.
Again, this makes no sense conceptually, because there’s an many-to-one relationship between users and your sysex.
For certificate-based authentication the SystemExtension needs to be
able to access and use a client certificate. Is there a recommended
way for the extension to access the client certificate, e.g, if the
extension starts without the GUI because of an on-demand VPN
configuration? In that case it doesn't seem like it would have
keychain access.
A sysex, like other daemon code, can only use the System keychain. This is a file-based keychain. See TN3137 On Mac keychain APIs and implementations for more background on this.
If the client identity is installed by a configuration profile and referenced by VPN configuration in that same profile, it should land in the System keychain in a way that your sysex can use it. I don’t remember ever confirming that for myself, and it wouldn’t surprise me if you ran into problems with it.
If your want to support other approaches — for example, adding a UI to your container app that lets the user create a VPN configuration including a selected client identity — that’s possible. However, you won’t be able to install the identity from your app because your app can’t modify the System keychain. Rather, you’d use IPC to pass the PKCS#12 to the daemon for it to import it into the System keychain.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"