How to sign a DEXT

This thread has been locked by a moderator; it no longer accepts new replies.

Kevin's Guide to DEXT Signing

The question of "How do I sign a DEXT" comes up a lot, so this post is my attempt to describe both what the issues are and the best current solutions are. So...

The Problems:

  1. When DEXTs were originally introduced, the recommended development signing process required disabling SIP and local signing. There is a newer, much simpler process that's built on Xcode's integrated code-signing support; however, that newer process has not yet been integrated into the documentation library. In addition, while the older flow still works, many of the details it describes are no longer correct due to changes to Xcode and the developer portal.

  2. DriverKit's use of individually customized entitlements is different than the other entitlements on our platform, and Xcode's support for it is somewhat incomplete and buggy. The situation has improved considerably over time, particularly from Xcode 15 and Xcode 16, but there are still issues that are not fully resolved.

To address #1, we introduced "development" entitlement variants of all DriverKit entitlements. These entitlement variants are ONLY available in development-signed builds, but they're available on all paid developer accounts without any special approval. They also allow a DEXT to match against any hardware, greatly simplifying working with development or prototype hardware which may not match the configuration of a final product.

Unfortunately, this also means that DEXT developers will always have at least two entitlement variants (the public development variant and the "private" approved entitlement), which is what then causes the problem I mentioned in #2.

The Automatic Solution:

If you're using Xcode 16 or above, then Xcode's Automatic code sign support will work all DEXT Families, with the exception of distribution signing the PCI and USB Families.

For completeness, here is how that Automatic flow should work:

  • Change the code signing configuration to "Automatic".

  • Add the capability using Xcode.

  • (USB & PCI) Edit your Entitlement.plist to include the correct "Development Only" configuration:

USB Development Only Configuration:

<key>com.apple.developer.driverkit.transport.usb</key>
<array>
   <dict>
	   <key>idVendor</key>
	   <string>*</string>
   </dict>
</array>

PCI Development Only Configuration:

<key>com.apple.developer.driverkit.transport.pci</key>
<array>
	<dict>
		<key>IOPCIPrimaryMatch</key>
		<string>0xFFFFFFFF&amp;0x00000000</string>
	</dict>
</array>

If you've been approved for one of these entitlements, the one oddity you'll see is that adding your approved capability will add both the approved AND the development variant, while deleting either will delete both. This is a visual side effect of #2 above; however, aside from the exception described below, it can be ignored.

Similarly, you can sign distribution builds by creating a build archive and then exporting the build using the standard Xcode flow.

Debugging Automatic Code-signing

In a new project, the flow I describe above should just work; however, if you're converting an existing project, you may get code signing errors, generally complaining about how the provisioning profile configuration doesn't match. In most cases, this happens because Xcode is choosing to reuse a previously downloaded profile with an older configuration instead of generating a new configuration which would then include the configuration changes you made.

Currently, you can find these profile files in:

~/Library/Developer/Xcode/UserData/Provisioning Profiles

...which can make it easier to find and delete the specific profile (if you choose). However, one recommendation I'd have here is to not treat the contents of that folder as "precious" or special. What automatic code signing actually does is generate provisioning profiles "on demand", so if you delete an automatic profile... Xcode will just generate it again at the next build. Manually generating profiles is more cumbersome, but the solution there is to preserve them as a separate resource, probably as part of your project data, NOT to just "lose" them in the folder here. If they get deleted from Xcode's store, then you can just copy them back in from your own store (or using Xcode, which can manually download profiles as well).

The advantage of this approach is that when profiles "pile up" over time (which they tend to do), you can just delete[1] all of them then let Xcode regenerate the ones you're actually trying to investigate.

In terms of looking at their contents, TN3125: Inside Code Signing: Provisioning Profiles has the details of how to see exactly what's there.

[1] Moving them somewhere else works too, but could indicate a fear of commitment.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Boost

Signing a distribution USB or PCI DEXT

The issues described above mean that the standard Xcode GUI flow cannot be used to directly export a distribution release of a USB or PCI DEXT. Here is that flow I've found that will work:

Note: The instructions below reference macOS-specific documentation, but the flow I'm describing was actually tested using an iOS project.

  1. Start by building the final version of your DEXT.

  2. On the portal, generate and download a provisioning profile for whatever environment you're going to try to build. Generate a profile for both the DEXT and the app it will be embedded in.

  3. Rename the DEXT profile you downloaded in #2 to "embedded.provisionprofile”.

  4. Show the packaged contents of your DEXT and replace the existing "embedded.provisionprofile" (development profile) profile with the file from #3 (the release profile).

  5. Use this command to resign the DEXT with the final entitlement configuration you'll be shipping. See the "Sign each code item" section of "Creating distribution-signed code for macOS" for more detailed guidance on constructing this command.

codesign -s <signing cert name> -f --timestamp -o runtime --entitlements <release entitlement.plist path> <dext path>
  1. Configure the project for your release project to use manual codesigning and the profile you app profile you downloaded in #2.

  2. Add the DEXT you resigned in #5 into your shipping project.

  3. Configure the "Copy Files" build phase to copy the DEXT as a System Extension.

  4. Archive the build.

  5. Use the Organizer to distribute the build to the same environment as the profile you generated in #2.

Note: The flow above relies on the fact that Xcode is using the DEXT's signing configuration "as is" instead of attempting to resign it. That means you'll need to go through the entire flow above for every build type you need to export (App Store, Mac App Store, Developer ID, Ad Hoc, etc.).

Debugging Export Failures

It is VERY likely that step #10 will fail, saying the entitlements don't match. This occurs because the entitlements.plist file you used in #5 did not EXACTLY match the configuration of the profiles Xcode needs/expects. This happens because you either:

  1. Didn't include "all" the necessary entitlements.

  2. The entitlement configuration isn't exactly right.

You can debug these issues using two tools:

  • The "Show Logs" button in the Xcode organizer will show you the detailed logs from Xcode. In my test, the issues were in "IDEDistribution.verbose.log", near the end of the log. Searching for "match" will get you to the entry, and replacing "\n" with a newline character will make the output readable. Add whatever entitlements are missing from this logging to correct #1 (I was missing several).

  • You can use the instructions found here to view the signing configuration of your archived build. This will let you sort out issues like format types (I had several issues here as well).

Note that in both cases the solution will involve changing the entitlement.plist configuration used in #5 above, NOT the provisioning profile. Quoting myself:

"One thing to be aware of here is that Xcode has a "bias" in the way it presents codesign errors where it assumes the Entitlement.plist is "correct" and the profile is "wrong". However, in practice that's basically "never" the case with DriverKit entitlements and tends to lead to a lot of "flailing" trying to somehow "fix" the provisioning profile..."

In practice, that means changes to the provisioning profile should only be necessary if the entitlement was granted with an incorrect configuration, in which case you'd need to submit a new entitlement request to get that issue corrected.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

How to sign a DEXT
 
 
Q